def g57_talus(rng):
"""TALUS -- rectangular blocks drop by gravity into columns and rest on
whichever neighbour is tallest beneath them, so each block's landing height
is set by the collision it lands on rather than by any global rule. A base
layer guarantees every column has settled scree; a second pass of taller
boulders piles up wherever the random drop lands, pushing some columns much
higher than their neighbours."""
N = rng.choice([24, 32, 40, 50])
c = Canvas(N, "GEOMETRIC", "squares", "talus", tiles=False)
C = c.C
heights = [0] * N # stacked height per column, in whole cells
def drop(w, h, shrink_lo, shrink_hi):
i = rng.randrange(N - w + 1)
cols = range(i, i + w)
base = max(heights[k] for k in cols)
if base + h > N:
return False
cx = i * C + w * C / 2.0
cy = 1000.0 - base * C - h * C / 2.0
bw = w * C * rng.uniform(shrink_lo, shrink_hi)
bh = h * C * rng.uniform(shrink_lo, shrink_hi)
c.rect(cx, cy, bw, bh)
for k in cols:
heights[k] = base + h
return True
base_lo, base_hi = rng.choice([(1, 2), (2, 3), (1, 3)])
order = list(range(N))
rng.shuffle(order)
for i in order:
h = rng.randint(base_lo, base_hi)
cx = i * C + C / 2.0
cy = 1000.0 - h * C / 2.0
bw = C * rng.uniform(0.80, 0.96)
bh = h * C * rng.uniform(0.80, 0.96)
c.rect(cx, cy, bw, bh)
heights[i] = h
wide_chance = rng.uniform(0.2, 0.5)
boulder_h_lo, boulder_h_hi = rng.choice([(1, 2), (2, 4), (1, 3)])
boulder_attempts = rng.randint(int(N * 1.6), int(N * 3.2))
for _ in range(boulder_attempts):
w = 2 if (rng.random() < wide_chance and N > 2) else 1
h = rng.randint(boulder_h_lo, boulder_h_hi)
drop(w, h, 0.78, 0.95)
return c