class=class="string">"comment">#!/usr/bin/env python3
"""
Fractal Garden: Generative art exploring mathematical beauty.

Creates evolving fractal patterns that feel organic and alive.
Each run produces a unique piece based on the timestamp.
"""

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
from datetime import datetime
import os
from pathlib import Path


class="keyword">def create_custom_colormap(seed):
    """Create a unique colormap based on seed."""
    np.random.seed(seed)

    class=class="string">"comment"># Generate colors with a coherent aesthetic
    base_hue = np.random.random()
    colors = []

    for i in range(5):
        h = (base_hue + i * 0.15) % 1.0
        s = 0.4 + np.random.random() * 0.4
        v = 0.6 + np.random.random() * 0.3

        class=class="string">"comment"># HSV to RGB conversion
        c = v * s
        x = c * (1 - abs((h * 6) % 2 - 1))
        m = v - c

        if h < 1/6:
            r, g, b = c, x, 0
        elif h < 2/6:
            r, g, b = x, c, 0
        elif h < 3/6:
            r, g, b = 0, c, x
        elif h < 4/6:
            r, g, b = 0, x, c
        elif h < 5/6:
            r, g, b = x, 0, c
        else:
            r, g, b = c, 0, x

        colors.append((r + m, g + m, b + m))

    return LinearSegmentedColormap.from_list(&class=class="string">"comment">#039;fractal&#039;, colors, N=256)


class="keyword">def mandelbrot(h, w, x_center, y_center, zoom, max_iter=256):
    """Generate Mandelbrot set with custom center and zoom."""
    x = np.linspace(x_center - 2/zoom, x_center + 2/zoom, w)
    y = np.linspace(y_center - 2/zoom, y_center + 2/zoom, h)
    X, Y = np.meshgrid(x, y)
    C = X + 1j * Y

    Z = np.zeros_like(C)
    M = np.zeros(C.shape)

    for i in range(max_iter):
        mask = np.abs(Z) <= 2
        Z[mask] = Z[mask] ** 2 + C[mask]
        M[mask] = i

    return M


class="keyword">def julia(h, w, c_real, c_imag, zoom=1.0, max_iter=256):
    """Generate Julia set for a given complex constant."""
    x = np.linspace(-2/zoom, 2/zoom, w)
    y = np.linspace(-2/zoom, 2/zoom, h)
    X, Y = np.meshgrid(x, y)
    Z = X + 1j * Y
    c = complex(c_real, c_imag)

    M = np.zeros(Z.shape)

    for i in range(max_iter):
        mask = np.abs(Z) <= 2
        Z[mask] = Z[mask] ** 2 + c
        M[mask] = i

    return M


class="keyword">def burning_ship(h, w, x_center, y_center, zoom, max_iter=256):
    """Generate Burning Ship fractal."""
    x = np.linspace(x_center - 2/zoom, x_center + 2/zoom, w)
    y = np.linspace(y_center - 2/zoom, y_center + 2/zoom, h)
    X, Y = np.meshgrid(x, y)
    C = X + 1j * Y

    Z = np.zeros_like(C)
    M = np.zeros(C.shape)

    for i in range(max_iter):
        mask = np.abs(Z) <= 2
        Z[mask] = (np.abs(Z[mask].real) + 1j * np.abs(Z[mask].imag)) ** 2 + C[mask]
        M[mask] = i

    return M


class="keyword">def create_garden(seed=None, output_dir=None):
    """Create a fractal garden image."""
    if seed is None:
        seed = int(datetime.now().timestamp())

    np.random.seed(seed)

    class=class="string">"comment"># Determine output directory
    if output_dir is None:
        output_dir = Path(__file__).parent.parent / "art"
    output_dir = Path(output_dir)
    output_dir.mkdir(exist_ok=True)

    class=class="string">"comment"># Image parameters
    h, w = 1000, 1400
    dpi = 100

    class=class="string">"comment"># Choose fractal type
    fractal_type = np.random.choice([&class=class="string">"comment">#039;mandelbrot&#039;, &#039;julia&#039;, &#039;burning_ship&#039;])

    class=class="string">"comment"># Generate fractal based on type
    if fractal_type == &class=class="string">"comment">#039;mandelbrot&#039;:
        class=class="string">"comment"># Interesting regions of Mandelbrot
        regions = [
            (-0.5, 0, 1),        class=class="string">"comment"># Classic view
            (-0.75, 0.1, 4),     class=class="string">"comment"># Sea horse valley
            (-1.25, 0.02, 10),   class=class="string">"comment"># Elephant valley
            (-0.16, 1.0405, 50), class=class="string">"comment"># Deep zoom
        ]
        x_c, y_c, zoom = regions[np.random.randint(len(regions))]
        M = mandelbrot(h, w, x_c, y_c, zoom)
        title = f"Mandelbrot at ({x_c:.3f}, {y_c:.3f})"

    elif fractal_type == &class=class="string">"comment">#039;julia&#039;:
        class=class="string">"comment"># Interesting Julia set constants
        constants = [
            (-0.8, 0.156),       class=class="string">"comment"># Classic
            (-0.4, 0.6),         class=class="string">"comment"># Dendrite
            (0.285, 0.01),       class=class="string">"comment"># Island
            (-0.70176, -0.3842), class=class="string">"comment"># Dragon
        ]
        c_r, c_i = constants[np.random.randint(len(constants))]
        zoom = 1 + np.random.random() * 2
        M = julia(h, w, c_r, c_i, zoom)
        title = f"Julia c=({c_r:.4f}, {c_i:.4f})"

    else:  class=class="string">"comment"># burning_ship
        regions = [
            (-0.5, -0.5, 1),
            (-1.755, -0.04, 20),
        ]
        x_c, y_c, zoom = regions[np.random.randint(len(regions))]
        M = burning_ship(h, w, x_c, y_c, zoom)
        title = f"Burning Ship at ({x_c:.3f}, {y_c:.3f})"

    class=class="string">"comment"># Create figure
    fig, ax = plt.subplots(figsize=(w/dpi, h/dpi), dpi=dpi)

    class=class="string">"comment"># Apply custom colormap
    cmap = create_custom_colormap(seed % 1000)

    class=class="string">"comment"># Normalize and apply log transform for better contrast
    M_normalized = np.log1p(M)

    class=class="string">"comment"># Plot
    ax.imshow(M_normalized, cmap=cmap, extent=[-2, 2, -2, 2])
    ax.set_axis_off()

    class=class="string">"comment"># Add subtle title
    fig.text(0.02, 0.02, title, fontsize=8, color=&class=class="string">"comment">#039;white&#039;, alpha=0.5)
    fig.text(0.98, 0.02, f&class=class="string">"comment">#039;seed: {seed}&#039;, fontsize=8, color=&#039;white&#039;, alpha=0.5, ha=&#039;right&#039;)

    plt.tight_layout(pad=0)

    class=class="string">"comment"># Save
    filename = f"fractal_{seed}.png"
    filepath = output_dir / filename
    plt.savefig(filepath, bbox_inches=&class=class="string">"comment">#039;tight&#039;, pad_inches=0, facecolor=&#039;black&#039;)
    plt.close()

    print(f"Created: {filepath}")
    return filepath


class="keyword">def create_gallery(count=4, output_dir=None):
    """Create a gallery of fractal images."""
    paths = []
    base_seed = int(datetime.now().timestamp())

    for i in range(count):
        path = create_garden(seed=base_seed + i, output_dir=output_dir)
        paths.append(path)

    print(f"\nGallery created with {count} images")
    return paths


class="keyword">def main():
    import sys

    if len(sys.argv) > 1 and sys.argv[1] == &class=class="string">"comment">#039;gallery&#039;:
        count = int(sys.argv[2]) if len(sys.argv) > 2 else 4
        create_gallery(count)
    else:
        create_garden()


if __name__ == "__main__":
    main()