Skip to content
Vamshi Jandhyala

Books · The Riddler

Chapter 241

What Are Your Chances Of Winning The U.S. Open?

Riddler Express

In “Acchi, Muite, Hoi” (the lookaway challenge), you and a friend alternate roles. The pointer points in one of four directions (up, down, left, right) while the looker simultaneously looks in one of the four. If the looker looks where the pointer points, the pointer wins; otherwise they swap roles and play again. You point first, and both of you choose randomly each round. What is your probability of winning?

The Riddler, FiveThirtyEight, September 6, 2019(original post)

Solution

It is not 50%50\%: pointing first is a real edge, because only the pointer can win a round. Let aa be the probability that whoever is currently pointing eventually wins the game. On this round the pointer wins outright with probability 14\tfrac14 (the directions match). With probability 34\tfrac34 no one wins, the roles swap, and the other player is now the pointer, who then wins with probability aa, so the current player wins with probability 1a1 - a. Hence a=14+34(1a)    74a=1    a=47.a = \tfrac14 + \tfrac34 (1 - a) \;\Longrightarrow\; \tfrac74 a = 1 \;\Longrightarrow\; a = \tfrac47. You are the first pointer, so your chance of winning is 4757.1%.\boxed{\tfrac47 \approx 57.1\%}. The same answer falls out of summing the odd rounds (you can only win when you point, in rounds 1,3,5,1, 3, 5, \ldots): 14(1+(34)2+(34)4+)=14119/16=47\tfrac14\bigl(1 + (\tfrac34)^2 + (\tfrac34)^4 + \cdots\bigr) = \tfrac14 \cdot \tfrac{1}{1 - 9/16} = \tfrac47.

The computation

Encode the actual game: alternate pointer and looker, each picking one of four directions at random, until a round’s directions match, and record whether the first pointer (you) won. The frequency should sit at 4/74/7.

import random
rng = random.Random(0); wins = 0; T = 2_000_000
for _ in range(T):
    pointer = 0                              # 0 = you, the first pointer
    while True:
        if rng.randrange(4) == rng.randrange(4):
            wins += (pointer == 0); break
        pointer ^= 1                          # no match: swap roles
print(f"simulated {wins / T:.4f}  vs  4/7 = {4/7:.4f}")
# simulated 0.5718  vs  4/7 = 0.5714

Riddler Classic

At the U.S. Open you win each point with probability 55%55\%. Tennis scoring: a game goes to 44 points, win by 22; a set goes to 66 games, win by 22, with a tiebreaker to 77 points (win by 22) at 66-66; a match is best of three sets (women) or best of five (men). What are your chances of winning a three-set match, a five-set match, and the whole tournament (seven straight matches)?

The Riddler, FiveThirtyEight, September 6, 2019(original post)

Solution

Tennis scoring is steeply nonlinear: a small per-point edge compounds through the nested “win by two” races. Work from the inside out. A game and a tiebreaker are both races to a target won by two; from a tied-near-the-top score (deuce), the chance of winning is q2/ ⁣(q2+(1q)2)q^2/\!\left(q^2 + (1-q)^2\right) with q=0.55q = 0.55, and unwinding the rest of the game gives the chance of holding from 00-00. Feeding the game probability into the same kind of race over games (with a tiebreaker at 66-66) gives the set probability, and from there the match and tournament follow.

Carried out with q=0.55q = 0.55, the chance of winning a set is about 81.5%81.5\%, and then

Playing more sets helps the stronger player, which is why the five-set tournament probability is so much higher. The lesson is that 55%55\% of points is not “slightly better”: it is roughly the career rate of the all-time greats.

The computation

Encode each “race to NN, win by 22” as a recursion on the current score, with the deuce region handled by its closed form, and compose: game and tiebreaker as point races, the set as a race over games (tiebreaker at 66-66), the match as best-of, the tournament as seven matches.

from functools import lru_cache
from math import comb
p = 0.55
def deuce(q): return q * q / (q * q + (1 - q) ** 2)
def race(q, N):                              # P(win race to N, win by 2) from 0-0
    @lru_cache(None)
    def f(a, b):
        if a >= N - 1 and b >= N - 1:
            d = a - b; D = deuce(q)
            return 1.0 if d >= 2 else 0.0 if d <= -2 else \
                   D if d == 0 else q + (1 - q) * D if d == 1 else q * D
        if a >= N and a - b >= 2: return 1.0
        if b >= N and b - a >= 2: return 0.0
        return q * f(a + 1, b) + (1 - q) * f(a, b + 1)
    return f(0, 0)

game, tb = race(p, 4), race(p, 7)
@lru_cache(None)
def setp(a, b):
    if a == 6 and b == 6: return tb           # tiebreaker
    if a >= 6 and a - b >= 2 or a == 7: return 1.0
    if b >= 6 and b - a >= 2 or b == 7: return 0.0
    return game * setp(a + 1, b) + (1 - game) * setp(a, b + 1)

s = setp(0, 0)
def match(n):                                 # best of (2n-1) sets
    return sum(comb(n - 1 + k, k) * s ** n * (1 - s) ** k for k in range(n))
m3, m5 = match(2), match(3)
print(f"set={s:.3f}  3-set={m3:.3f}  5-set={m5:.3f}")
print(f"tournament women={m3**7:.3f}  men={m5**7:.3f}")
# set=0.815  3-set=0.910  5-set=0.953
# tournament women=0.517  men=0.714

The recursion reproduces the 81.5%81.5\% set, the 91.0%91.0\% and 95.3%95.3\% matches, and the 51.7%51.7\% and 71.4%71.4\% tournament chances.