def g59_automaton(rng):
"""AUTOMATON — a random binary field run under a majority-of-8 rule, ties at
the threshold holding their previous value, until it locks into a fixed
point or a short cycle. Settled cells shade by their final neighbour count,
so blob interiors run dark and their margins stay light; the starting
density is redrawn, still from the same seed, until the settled field
occupies a workable fraction of the canvas."""
N = rng.choice([32, 40, 50])
c = Canvas(N, "GLYPH", "glyph", "automaton", tiles=True)
NX, NY = c.cols, c.rows
lo = 4
def settle(density):
grid = [[1 if rng.random() < density else 0 for _ in range(NY)] for _ in range(NX)]
seen = []
for step in range(60):
cnt = [[0] * NY for _ in range(NX)]
for i in range(NX):
for j in range(NY):
n = 0
for di in (-1, 0, 1):
for dj in (-1, 0, 1):
if di == 0 and dj == 0:
continue
ii, jj = (i + di) % NX, (j + dj) % NY
if grid[ii][jj]:
n += 1
cnt[i][j] = n
nxt = [[0] * NY for _ in range(NX)]
for i in range(NX):
for j in range(NY):
n = cnt[i][j]
if n > lo:
nxt[i][j] = 1
elif n == lo:
nxt[i][j] = grid[i][j]
else:
nxt[i][j] = 0
changed = any(nxt[i][j] != grid[i][j] for i in range(NX) for j in range(NY))
grid = nxt
if not changed:
break
key = tuple(tuple(row) for row in grid)
if key in seen:
break
seen.append(key)
if len(seen) > 3:
seen.pop(0)
cnt = [[0] * NY for _ in range(NX)]
alive = 0
for i in range(NX):
for j in range(NY):
n = 0
for di in (-1, 0, 1):
for dj in (-1, 0, 1):
if di == 0 and dj == 0:
continue
ii, jj = (i + di) % NX, (j + dj) % NY
if grid[ii][jj]:
n += 1
cnt[i][j] = n
alive += grid[i][j]
return grid, cnt, alive / (NX * NY)
best = None
for _ in range(14):
density = rng.uniform(0.30, 0.62)
grid, cnt, frac = settle(density)
score = abs(frac - 0.45)
if best is None or score < best[0]:
best = (score, grid, cnt, frac)
if 0.32 <= frac <= 0.58:
break
_, grid, cnt, frac = best
R = ramp(["x", "o", "#", "@", "▒", "▀", "▓", "█"])
lo_i, hi_i = 0, len(R) - 1
for i in range(NX):
for j in range(NY):
if not grid[i][j]:
continue
t = clamp((cnt[i][j] - lo) / (8 - lo))
idx = lo_i + int(round(t * (hi_i - lo_i)))
c.glyph(i, j, R[idx])
return c