patterns — jamslide

generator verdict no votes yet
source — auto/a004_jamslide.g54_jamslide
def g54_jamslide(rng):
    """jamslide -- collision-halted sliding particles.
    Particles spawn at random lattice cells and slide in a straight direction until they
    hit the canvas edge or an already-settled particle, then lock in place. Each resting
    particle is drawn as a square or dot sized by how far it traveled before the collision.
    """
    N = rng.choice([16, 20, 24, 32, 40, 50])
    use_circles = rng.random() < 0.5
    primitive = "dots" if use_circles else "squares"
    c = Canvas(N, "GEOMETRIC", primitive, "jamslide", tiles=False)

    eight_way = rng.random() < 0.4
    dirs = [(1, 0), (-1, 0), (0, 1), (0, -1)]
    if eight_way:
        dirs += [(1, 1), (1, -1), (-1, 1), (-1, -1)]

    coverage_target = rng.uniform(0.30, 0.48)
    fill_target = rng.uniform(0.4, 0.8)
    area_frac = clamp(coverage_target / fill_target, 0.3, 0.92)
    base_size = math.sqrt(area_frac)

    tumble = rng.random() < 0.5

    total_cells = N * N
    n_particles = max(1, int(total_cells * fill_target))

    order = [(i, j) for i in range(N) for j in range(N)]
    rng.shuffle(order)

    occupied = [[False] * N for _ in range(N)]
    placements = []

    for (i0, j0) in order:
        if len(placements) >= n_particles:
            break
        if occupied[i0][j0]:
            continue
        dx, dy = rng.choice(dirs)
        i, j = i0, j0
        dist = 0
        while True:
            ni, nj = i + dx, j + dy
            if ni < 0 or ni >= N or nj < 0 or nj >= N or occupied[ni][nj]:
                break
            i, j = ni, nj
            dist += 1
        occupied[i][j] = True
        placements.append((i, j, dist))

    max_dist = max((p[2] for p in placements), default=0)
    if max_dist == 0:
        max_dist = 1

    for (i, j, dist) in placements:
        cx, cy = c.center(i, j)
        frac = dist / max_dist
        size_frac = clamp(base_size * (0.85 + 0.3 * frac), 0.2, 0.97)
        side = c.C * size_frac
        if use_circles:
            c.circle(cx, cy, side / 2)
        else:
            rot = 45 if tumble else None
            c.rect(cx, cy, side, side, rot=rot)

    return c
jamslide-squares-32-cb37
jamslide-squares-32-cb37
jamslide-squares-16-6b96
jamslide-squares-16-6b96
jamslide-dots-20-fe52
jamslide-dots-20-fe52
jamslide-squares-16-195b
jamslide-squares-16-195b
jamslide-dots-24-b7ec
jamslide-dots-24-b7ec
jamslide-squares-32-0e56
jamslide-squares-32-0e56
jamslide-squares-32-d341
jamslide-squares-32-d341

generator