Chapter 179
Shut the Box
Riddler Classic
Shut the Box has tiles, numbered through , all starting open. On each turn you roll two dice and shut any combination of open tiles whose values sum to the dice total. Once are all shut you may choose to roll one or two dice; otherwise you must roll both. The game ends when you shut every tile (you win) or you cannot shut a subset summing to the roll (you lose). What is your probability of winning under perfect play?
The Riddler, FiveThirtyEight, April 13, 2018(original post)
The Riddler Express that week asked which two-card Texas Hold’em starting hand most often makes the nuts. The published answer is suited (with the argument that the nut flush dominates the count). A careful Monte-Carlo over full -card boards in fact ranks suited above suited as the most frequent nut-making starting hand, with the difference driven by straight-and-flush coverage rather than nut-flush coverage alone. Because we have not resolved this discrepancy with the official to certainty, the Express is deferred.
Solution
The state space. The position of the game is the set of still-open tiles. There are states; the empty set is the winning terminal. Let denote the probability of eventually winning from state under optimal play.
The Bellman equation. From state , the player chooses how many dice to roll (constrained: two dice unless , in which case either one or two), then observes the total , then picks a subset with to shut. If no such exists for a given , that roll loses.
For two dice the total has the standard distribution with for . For one die, for . Write the per-roll value at for dice as with the convention that an empty maximum (no shutting subset exists) contributes . Then This is a straight dynamic programme on states. Each state’s update requires enumerating shutting subsets summing to each total, which is fast.
The headline. Solving the DP gives The starting-state value is the win probability under perfect play. The official quotes the same .
Where the choice of vs dice matters. Among the states where the choice is available (those with all shut), the optimal choice depends on . With many small tiles still open, two dice (which average ) is dangerous; one die (averaging ) gives a better chance of hitting an achievable total. With only large tiles left, two dice gives the only reach to the needed totals.
The computation
Directly solve the DP described above.
Enumerate every state in order of increasing so that is known when computing .
For each , compute the candidate per-roll values (when allowed) and , taking the max over shutting subsets at each total.
Return .
from functools import lru_cache
ALL = frozenset(range(1, 10))
def subsets_summing_to(open_set, target):
open_list = sorted(open_set)
results = []
def rec(i, cur, s):
if s == target:
results.append(frozenset(cur)); return
if s > target or i == len(open_list): return
rec(i + 1, cur, s)
rec(i + 1, cur + [open_list[i]], s + open_list[i])
rec(0, [], 0)
return results
DICE2 = {t: 0 for t in range(2, 13)}
for d1 in range(1, 7):
for d2 in range(1, 7):
DICE2[d1 + d2] += 1
@lru_cache(maxsize=None)
def V(S):
if not S: return 1.0
can_one = all(x not in S for x in (7, 8, 9))
def per_roll(ndice):
if ndice == 1:
tot = 0.0
for r in range(1, 7):
subs = subsets_summing_to(S, r)
if subs:
tot += max(V(S - s) for s in subs)
return tot / 6
tot = 0.0
for t, n in DICE2.items():
subs = subsets_summing_to(S, t)
if subs:
tot += n * max(V(S - s) for s in subs)
return tot / 36
return max(per_roll(2), per_roll(1)) if can_one else per_roll(2)
print(f"V(all open) = {V(ALL):.6f}")
The script prints , matching the boxed .