day 21
dirac dice
approach
part 1 is a straight simulation with a deterministic die: each turn rolls three consecutive numbers, moves around a 10-space track, and stops once someone reaches 1000.
part 2 splits the universe on every roll of a 3-sided die. three rolls only produce sums 3–9, with known frequencies (1, 3, 6, 7, 6, 3, 1 ways), so the solution recurses on (score1, score2, pos1, pos2, turn), multiplying each branch by how many universes reach it. lru_cache collapses the repeated states, and it returns win counts for both players as a vector.
the trick
roll the three dice together: 27 universes collapse into 7 outcomes with weights, and memoization does the rest.
python
for k, v in [(3,1),(4,3),(5,6),(6,7),(7,6),(8,3),(9,1)]:
np = (p1 + k) % 10
ns = s1 + np + 1
s = s.add(dp(ns, s2, np, p2, 1).scale(v))