def g60_erode(rng):
"""ERODE — a full field is carved by drainage channels descending a noise
elevation, each channel stepping to its steepest downhill lattice neighbour
and cutting the cell it leaves at a strength that grows the longer the
channel has run, so tributaries that merge cut deeper than lone streams and
the field reads as high ground eaten back to bare rock along the runoff."""
N = rng.choice([32, 40, 50])
c = Canvas(N, "GLYPH", "glyph", "erode", tiles=False)
NX, NY = c.cols, c.rows
nz = Value2D(rng, res=rng.choice([3, 4, 5]))
elev = [[nz((i + 0.5) / NX, (j + 0.5) / NY) for j in range(NY)] for i in range(NX)]
material = [[1.0] * NY for _ in range(NX)]
flow = [[0] * NY for _ in range(NX)]
dirs8 = [(1, 0), (-1, 0), (0, 1), (0, -1), (1, 1), (-1, -1), (1, -1), (-1, 1)]
n_sources = rng.randint(int(NX * NY * 0.05), int(NX * NY * 0.12))
steps = rng.randint(int((NX + NY) * 0.8), (NX + NY) * 2)
cut = rng.uniform(0.05, 0.11)
grow = rng.uniform(0.01, 0.035)
floor = rng.uniform(0.04, 0.12)
for _ in range(n_sources):
i, j = rng.randrange(NX), rng.randrange(NY)
power = cut
for _ in range(steps):
flow[i][j] += 1
material[i][j] = max(floor, material[i][j] - power)
power += grow
here = elev[i][j]
best, bd = None, here
for dx, dy in dirs8:
ni, nj = i + dx, j + dy
if 0 <= ni < NX and 0 <= nj < NY and elev[ni][nj] < bd:
bd = elev[ni][nj]
best = (ni, nj)
if best is None:
break
i, j = best
ramp_chars = ramp([".", ":", "-", "+", "x", "o", "#", "▒"])
base_idx = rng.randint(5, 7)
floor_idx = rng.randint(0, 1)
span = base_idx - floor_idx
for i in range(NX):
for j in range(NY):
t = clamp((material[i][j] - floor) / (1.0 - floor))
k = floor_idx + int(round(t * span))
c.glyph(i, j, ramp_chars[k])
return c