Chapter 283
Is The Price Right?
The Riddler for October 16, 2020. The Express finds the chance of a three-way election going to a runoff, and the Classic solves a sequential “Price is Right” bidding game for the first guesser’s odds.
Riddler Express
Riddler City elects a mayor from three candidates. A candidate wins outright with more than of the vote; otherwise the top two go to a runoff. If the three vote shares are uniformly distributed (subject to summing to ), what is the probability of a runoff?
The Riddler, FiveThirtyEight, October 16, 2020(original post)
Solution
The three shares with live uniformly on an equilateral triangle (the -simplex). A runoff happens exactly when no share exceeds . The region where a particular share, say , is the corner triangle similar to the whole with half the side, hence of the area; the three such corner triangles are disjoint (two shares cannot both exceed ). So an outright majority occupies of the simplex, and the runoff region is the central medial triangle,
The computation
Encode the model: sample shares uniformly on the simplex (sort two uniforms to split into three parts) and check whether all stay below .
import random
rng = random.Random(0)
trials, runoff = 2_000_000, 0
for _ in range(trials):
a, b = sorted((rng.random(), rng.random()))
shares = (a, b - a, 1 - b) # uniform on the 2-simplex
if max(shares) <= 0.5:
runoff += 1
print(round(runoff / trials, 4)) # ~0.25
The simulation sits at : a runoff happens a quarter of the time.
Riddler Classic
You and two others guess the price of an item, one at a time; the true price is uniform on . The winner is whoever guesses closest without going over; if all three overshoot, the lowest guess wins. You guess first, and everyone plays optimally, using the earlier guesses. What is your probability of winning?
The Riddler, FiveThirtyEight, October 16, 2020(original post)
Solution
Work backwards. After the first two guesses split into three intervals (below both, between, above both), the third player simply claims whichever interval is widest, by guessing , a hair above the lower guess, or a hair above the higher guess. Knowing this, the second player picks a guess to maximise their own interval, and you, guessing first, anticipate both.
The first guesser’s best move is . The second then guesses , which cuts into three intervals of equal width . With all three gaps equal, the last player is indifferent and takes exactly one third, leaving one third for each of you. So every player, including the first, wins with probability Any other opening lets the later players, who see your guess, carve out more than a third at your expense, so is the best you can guarantee.
The computation
Encode the payoff: for fixed guesses, integrate over the uniform price to get each player’s win probability. Then verify that the equilibrium guesses make all three intervals equal, so whichever gap the last player grabs, everyone gets .
def shares(gA, gB, gC):
players = [('A', gA), ('B', gB), ('C', gC)]
cuts = sorted({0.0, 100.0, gA, gB, gC})
win = {'A': 0.0, 'B': 0.0, 'C': 0.0}
for lo, hi in zip(cuts, cuts[1:]):
t = (lo + hi) / 2 # a representative price
under = [(g, who) for who, g in players if g <= t]
winner = max(under)[1] if under else min(players, key=lambda x: x[1])[0]
win[winner] += (hi - lo) / 100
return win
A, B, eps = 200 / 3, 100 / 3, 1e-9
print(round(B, 1), round(A - B, 1), round(100 - A, 1)) # 33.3 33.3 33.3
for C in (0.0, B + eps): # last player guesses low, e.g. 0 (per official)
s = shares(A, B, C)
print({k: round(v, 3) for k, v in s.items()}) # 1/3 each
The three gaps are equal, so the last player’s natural low guess leaves each player, the first included, a chance.