patterns — shove

generator verdict no votes yet
source — auto/a006_shove.g56_shove
def g56_shove(rng):
    """SHOVE -- particles dropped at random points repel each other by a short-range
    force until they settle into an uneven equilibrium spacing; each cell's glyph
    weight comes from its rank in the settled pressure field, so tight knots where
    particles jammed together read dark and the gaps they shoved open read light."""
    N = rng.choice([24, 32, 40, 50])
    c = Canvas(N, "GLYPH", "glyph", "shove", tiles=False)
    NX, NY = c.cols, c.rows

    n = rng.choice([12, 16, 22, 28, 34])
    pts = [[rng.uniform(0.0, NX), rng.uniform(0.0, NY)] for _ in range(n)]

    reach = rng.uniform(3.5, 8.0)
    strength = rng.uniform(0.6, 1.3)
    iters = rng.choice([25, 35, 50])

    for _ in range(iters):
        fx = [0.0] * n
        fy = [0.0] * n
        for a in range(n):
            ax, ay = pts[a]
            for b in range(a + 1, n):
                dx = ax - pts[b][0]
                dy = ay - pts[b][1]
                d = math.sqrt(dx * dx + dy * dy) + 1e-6
                if d < reach:
                    push = strength * (reach - d) / reach
                    ux, uy = dx / d, dy / d
                    fx[a] += ux * push
                    fy[a] += uy * push
                    fx[b] -= ux * push
                    fy[b] -= uy * push
        for i in range(n):
            pts[i][0] = clamp(pts[i][0] + fx[i], 0.0, NX - 1e-6)
            pts[i][1] = clamp(pts[i][1] + fy[i], 0.0, NY - 1e-6)

    sigma = rng.uniform(1.3, 2.6)
    twosig2 = 2.0 * sigma * sigma
    field = [[0.0] * NY for _ in range(NX)]
    for i in range(NX):
        cx = i + 0.5
        for j in range(NY):
            cy = j + 0.5
            v = 0.0
            for (px, py) in pts:
                dx = cx - px
                dy = cy - py
                v += math.exp(-(dx * dx + dy * dy) / twosig2)
            field[i][j] = v

    flat = [(field[i][j], i, j) for i in range(NX) for j in range(NY)]
    flat.sort(key=lambda t: t[0])
    total = len(flat)

    chars = ramp([" ", ".", ":", "+", "x", "o", "#", "▒", "▓", "█"])
    k = len(chars)
    gamma = rng.uniform(0.55, 1.35)

    for idx, (v, i, j) in enumerate(flat):
        p = (idx + 0.5) / total
        p = p ** gamma
        bucket = min(k - 1, int(p * k))
        ch = chars[bucket]
        if ch != " ":
            c.glyph(i, j, ch)

    return c
shove-glyph-50-9293
shove-glyph-50-9293
shove-glyph-24-605e
shove-glyph-24-605e
shove-glyph-40-e0c8
shove-glyph-40-e0c8

generator