def g51_accrete(rng):
"""Accrete — multi-seed Eden growth; each cell's ramp step is its arrival time.
A handful of seed cells grow outward one random frontier cell at a time,
like invasion percolation. The fill order, ranked and reshaped by a random
exponent, becomes the ramp step, so the earliest growth reads darkest and
the outer shell reads lightest. A dot marks each seed once growth is laid.
"""
N = rng.choice([30, 40, 50])
steps = rng.randint(6, 10)
c = Canvas(N, rng.choice(PALETTE_NAMES), steps, "accrete", "dots")
moore = rng.random() < 0.5
deltas = ([(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)]
if moore else [(-1, 0), (1, 0), (0, -1), (0, 1)])
nseeds = rng.randint(2, 6)
seeds = set()
while len(seeds) < nseeds:
seeds.add((rng.randrange(N), rng.randrange(N)))
seeds = list(seeds)
arrival = [[-1] * N for _ in range(N)]
order = 0
frontier = []
infront = set()
for (si, sj) in seeds:
arrival[si][sj] = order
order += 1
def push(i, j):
for (di, dj) in deltas:
ni, nj = i + di, j + dj
if 0 <= ni < N and 0 <= nj < N and arrival[ni][nj] == -1 and (ni, nj) not in infront:
frontier.append((ni, nj))
infront.add((ni, nj))
for (si, sj) in seeds:
push(si, sj)
while frontier:
idx = rng.randrange(len(frontier))
frontier[idx], frontier[-1] = frontier[-1], frontier[idx]
i, j = frontier.pop()
infront.discard((i, j))
if arrival[i][j] != -1:
continue
arrival[i][j] = order
order += 1
push(i, j)
total = N * N
gamma = rng.uniform(0.85, 1.05)
def band(i, j):
t = (arrival[i][j] / (total - 1)) ** gamma
return min(steps - 1, int(t * steps))
c.ground(band)
r = c.C * rng.uniform(0.45, 0.75)
for (si, sj) in seeds:
cx, cy = c.center(si, sj)
c.dot(cx, cy, r, steps - 1)
return c