Chapter 81
Can You Win Riddler Jenga?
Riddler Express
Seven three-digit numbers fill a CrossProduct table. The products of each row’s digits are , and the products down the hundreds, tens and ones columns are , , . Find the seven numbers.
Solution
Factor each row product into three digits and let the column products select the right factorisation, pruning whenever a running column product overshoots. The search returns a unique table:
The computation
List each row’s digit triples, then search for the combination whose three columns multiply to the targets.
from itertools import product
rows = [280, 168, 162, 360, 60, 256, 126]
cols = (183708, 245760, 117600)
opts = [[(a, b, c) for a in range(1, 10) for b in range(1, 10)
for c in range(1, 10) if a*b*c == p] for p in rows]
sols = []
def search(i, prod, acc):
if any(prod[k] > cols[k] for k in range(3)): return
if i == 7:
if prod == list(cols): sols.append(acc)
return
for t in opts[i]:
search(i + 1, [prod[k]*t[k] for k in range(3)], acc + [t])
search(0, [1, 1, 1], [])
print(sols[0])
Riddler Classic
Stack blocks one at a time; each new block’s centre lands at a uniformly random point along the block directly beneath it. On average, how many blocks must you place before the tower first collapses (some block falls off)?
Solution
A tower stands only if every group of blocks from the top down rests stably on the block beneath it. Concretely, take the top blocks as a single rigid composite; it sits on the -th block from the top, and it topples if its centre of mass falls outside that supporting block’s footprint. The tower survives a new placement only when no such top group is overbalanced; the first time one is, those blocks tip and the tower collapses.
There is no tidy closed form, so simulate the process: drop blocks with random offsets and, after each, test every top group for an overhanging centre of mass. Averaging the collapse height over many towers, The tower usually survives the first few blocks easily, but each addition shifts some composite’s balance point, and the random walk of centres soon pushes one past its support.
The computation
Build towers block by block; after each block, check whether the centre of mass of any top group lies beyond the block supporting it, and record the height at first collapse.
import numpy as np
rng = np.random.default_rng(0)
def jenga(runs=1_000_000, cap=60):
active = np.ones(runs, bool); x = np.zeros((runs, 1))
result = np.zeros(runs, int); nb = 1
while active.any() and nb < cap:
x = np.concatenate([x, x[:, -1:] + rng.uniform(-1, 1, (runs, 1))], 1)
nb += 1
rev = np.cumsum(x[:, ::-1], 1)[:, ::-1]
cm = rev / np.arange(nb, 0, -1) # CM of blocks i..top
bad = np.zeros(runs, bool)
for i in range(1, nb): # group on block i-1
bad |= (cm[:, i] < x[:, i-1] - 1) | (cm[:, i] > x[:, i-1] + 1)
fell = active & bad
result[fell] = nb; active &= ~fell
result[result == 0] = nb
return result.mean()
print(jenga()) # ~7.1