Chapter 194
Step 1: Game Theory. Step 2: Step 3: Profit!
Riddler Express
Pull the nine numbered cards from one suit of a deck. Shuffle them, lay them face down in a row, and flip the first. Now guess whether the next card is bigger or smaller; if right, continue. Playing optimally, what is your probability of running the table without a mistake? What about through in general?
The Riddler, FiveThirtyEight, August 17, 2018(original post)
Solution
The optimal strategy is the obvious one: at every step, guess the side with more cards remaining (and break ties however you like). Among the cards you have not yet seen, more are bigger than the current upturned card or more are smaller; calling the bigger side gives you the better chance to survive this guess, and shrinks the remaining deck in the most informative way. We need to count the permutations on which this strategy never errs.
Let be the number of winning permutations of the cards . Refine to , the number of winning permutations whose first card is the -th smallest, for . Symmetry under swaps "bigger" and "smaller", so : the table is left-right symmetric.
If the first card is the smallest () or the largest (), the strategy’s first guess is determined and is certainly correct. The remaining problem is to play the bigger-or-smaller game on the remaining cards starting with their first turn; that first turn is a fresh game on cards whose own first card can be anything. So For interior , the first guess can fail. When the first card is the -th smallest with in the lower half, the strategy calls "bigger", and the next card must come from the cards above the current value, after which the remaining -card subproblem is played on the cards above the current floor. A careful accounting shows the entries of the table satisfy a Hudson-pyramid rule: each interior left-half entry equals the sum of the previous row entries to its right (and symmetrically on the right half). With the boundary rule , the table builds quickly: Each row sum is . The row sums are For ,
Asymptotically the win probability decays roughly like for a fixed ; numerically the rate is about . By the win probability is already below , by it is astronomically small.
The computation
A direct enumeration of all permutations confirms the answer.
For each permutation of , simulate the bigger-or-smaller game with the majority-call strategy.
Count permutations that survive every guess.
import itertools
def winning_count(cards):
cards = tuple(sorted(cards))
wins = 0
total = 0
for perm in itertools.permutations(cards):
total += 1
remaining = list(cards)
history = []
ok = True
for i, c in enumerate(perm):
if i > 0:
bigger = sum(1 for x in remaining if x > history[-1])
smaller = sum(1 for x in remaining if x < history[-1])
guess = 'B' if bigger >= smaller else 'S'
actual = 'B' if c > history[-1] else 'S'
if actual != guess:
ok = False; break
remaining.remove(c)
history.append(c)
if ok: wins += 1
return wins, total
for n in [3, 4, 5, 6, 7]:
w, t = winning_count(list(range(2, 2 + n)))
print(f"n={n}: wins={w}, total={t}, p={w/t:.4f}")
w, t = winning_count(list(range(2, 11)))
print(f"n=9: wins={w}, total={t}, p={w/t:.4f}")
The script prints
n=3: wins=5, total=6, p=0.8333
n=4: wins=16, total=24, p=0.6667
n=5: wins=62, total=120, p=0.5167
n=6: wins=286, total=720, p=0.3972
n=7: wins=1519, total=5040, p=0.3014
n=9: wins=62000, total=362880, p=0.1709
which matches the headline.
Riddler Classic
Ariel, Beatrice and Cassandra place stacks of $ on , $ on , and so on up to $ on along a number line. They take turns, in that order, placing one personal token on a stack. After all three tokens are placed, each player collects every stack closest to her token; midway-tied stacks are split. Each plays to maximise her own take. Where do they place, and how much does Ariel win?
The Riddler, FiveThirtyEight, August 17, 2018(original post)
Solution
A three-stage backward induction settles the game. There are only ordered triples of distinct positions to consider, so the game can be solved exhaustively, but the reasoning is also clean once you see Ariel’s idea.
Stage 3 (Cassandra). Given Ariel at and Beatrice at , Cassandra picks the position maximising her take. The number line splits into intervals at the midpoints of consecutive tokens, and each player gets her interval. Cassandra always slots in next to one of the existing tokens to seize the empty side of the line.
Stage 2 (Beatrice). Beatrice anticipates Cassandra’s best response and chooses to maximise her own take given that response.
Stage 1 (Ariel). Ariel anticipates both. Her instinct is to split the line so that the high half is left for Beatrice and Cassandra to fight over, while she scoops the low half. If Ariel sits at , the low half is worth , and the high half is worth . Beatrice and Cassandra will not abandon the high half because each $ there is worth more than each $ in the low half; in fact, they will both place in the high half, and Ariel’s midpoint with whichever of them is closest brings her one or two of the middle stacks as bonus. Specifically, with , Beatrice optimally places at , and Cassandra at . The midpoints fall at and , so Ariel takes for $, Cassandra takes for $, and Beatrice takes for $.
Going first pays an unexpected dividend. Ariel banks $, Beatrice (second) banks $, Cassandra (third) banks $. With three equal-skill players you might guess later movers would profit from better information, but on the line the right-half "money" is so valuable that the second and third movers waste their advantage chasing each other.
Note that the game is not symmetric under reflection: stack values grow with position, so the right end is the heavy end. Ariel’s is the unique optimum: it sits at the very edge of the heavy half, so the midpoint to any token Beatrice or Cassandra plants to her right falls past , sweeping the lower stacks into Ariel’s interval.
The computation
Backward induction over the ordered placements: for each Ariel position, compute Beatrice’s best, given which Cassandra has a best, given which Ariel evaluates her take.
Enumerate triples of distinct positions in .
Compute payoffs from token positions by assigning each stack to its closest token (splitting ties evenly).
Backward-induct.
POS = list(range(1, 11))
def payoffs(tokens):
pay = [0.0, 0.0, 0.0]
for stack in POS:
d = [abs(stack - t) for t in tokens]
m = min(d)
winners = [i for i, di in enumerate(d) if di == m]
share = stack / len(winners)
for w in winners: pay[w] += share
return tuple(pay)
def C_best(a, b):
best = -1.0; best_c = None
for c in POS:
if c in (a, b): continue
p = payoffs((a, b, c))
if p[2] > best:
best = p[2]; best_c = c
return best_c
def B_best(a):
best = -1.0; best_b = None; best_c = None
for b in POS:
if b == a: continue
c = C_best(a, b)
p = payoffs((a, b, c))
if p[1] > best:
best = p[1]; best_b = b; best_c = c
return best_b, best_c
best = -1.0; best_a = None; result = None
for a in POS:
b, c = B_best(a)
p = payoffs((a, b, c))
if p[0] > best:
best = p[0]; best_a = a; result = (b, c, p)
b, c, p = result
print(f"Ariel plays {best_a}, Beatrice plays {b}, Cassandra plays {c}")
print(f"payoffs: A=${p[0]}, B=${p[1]}, C=${p[2]}")
The script prints
Ariel plays 5, Beatrice plays 9, Cassandra plays 8
payoffs: A=$21.0, B=$19.0, C=$15.0
matching the headline.