Library · The Fiddler: Solutions · Chapter 109

Can You Fail to Lose the Tennis Match?

Revised Report an error

Consider a three-set tennis match. To win the match, you must win at least two of the three sets. A set is won by winning games, and a game by winning points.

A game is won by the first player to score four points, but the winner must win by two: if both players have three points, play continues until one of them is two points ahead. A set is won by the first player to win six games. However, if both players reach five games each, they play exactly two more games. If one player wins both, that player wins the set. If they win one each, so that it is six games all, they play a tiebreak. A tiebreak is a game played to seven points instead of four, again won by two.

What is the greatest percentage of points (tiebreak points included) a player could lose in a three-set match while still winning the match?

The Fiddler, Zach Wissner-Gross, July 12, 2024(original post)

The official solution appeared in the post of July 19, 2024 and gives 106/168≈63.1%106/168 \approx 63.1\%, agreeing with the answer below. The Extra Credit half of that post is paywalled, so the probability of about 6.27%6.27\% is my own.

Solution

Building a candidate. To lose many points and still win, you want to win as few sets as possible, so play all three and lose one of them. Lose that set as badly as the rules allow: six games to love, every game to love, which is 00 points won and 2424 lost.

The two sets you win should be as close as possible, so let each go to a tiebreak. Before it, each side wins six games. Lose your six games to love again (00 won, 2424 lost). Win your six games as narrowly as possible. A game cannot be won 44–33, because of the win-by-two rule, so the narrowest wins are 44–22, 55–33, 66–44 and so on. Take 44–22 for now (2424 won, 1212 lost). Win the tiebreak 77–55 (77 won, 55 lost). Each won set then has 3131 points won and 4141 lost. The whole match has 2×31=622 \times 31 = 62 points won and 2×41+24=1062 \times 41 + 24 = 106 lost, so the share lost is 10662+106  =  106168  =  5384.\frac{106}{62 + 106} \;=\; \frac{106}{168} \;=\; \frac{53}{84} .

Is that the best? Longer deuce games look tempting, since a game won 1111–99 loses a larger share of its own points than a game won 44–22. But the extra points come in pairs, one each, and a pair of points pulls the overall share toward one half. Our share is already well above one half, so the pairs can only hurt. The weighting argument below turns this into a proof that covers every possible match at once.

The proof. Write WW for the points you win and LL for the points you lose. The share lost is at most 5384\frac{53}{84} exactly when 84L≤53(W+L)84L \le 53(W + L), that is, when 31L−53W  ≤  0.31L - 53W \;\le\; 0 . So give every point you lose a score of +31+31 and every point you win a score of −53-53, and show that the total is never positive in a match you win. (The weights 3131 and 5353 are chosen so that the candidate above scores exactly zero.) Because scores add up, it is enough to find the highest score each piece of the match can reach.

piece best case highest score
game you win 44–22 −212+62=−150-212 + 62 = -150
game you lose 00–44 +124+124
tiebreak you win 77–55 −371+155=−216-371 + 155 = -216
tiebreak you lose 00–77 +217+217

Each line needs a word of justification. A game you win ends 44–kk with k≤2k \le 2, scoring 31k−212≤−15031k - 212 \le -150, or ends after deuce at (n+2)(n+2)–nn with n≥3n \ge 3, scoring 31n−53n−106=−22n−106≤−17231n - 53n - 106 = -22n - 106 \le -172. A game you lose ends kk–44 with k≤2k \le 2, scoring 124−53k≤124124 - 53k \le 124, or nn–(n+2)(n+2) with n≥3n \ge 3, scoring 62−22n<062 - 22n < 0. Tiebreaks work the same way with 77 in place of 44: a win scores at most 31⋅5−371=−21631 \cdot 5 - 371 = -216 (an extended one −22n−106-22n - 106 with n≥6n \ge 6, lower still), and a loss at most 217217.

Now the sets. A set you win ends 66–kk with k≤4k \le 4, or 77–55, or 77–66 after a tiebreak. Its highest scores are 6–4:6(−150)+4(124)=−404,7–5:7(−150)+5(124)=−430,7–6:6(−150)+6(124)−216=−372,\begin{align*} 6\text{--}4: &\quad 6(-150) + 4(124) = -404, \\ 7\text{--}5: &\quad 7(-150) + 5(124) = -430, \\ 7\text{--}6: &\quad 6(-150) + 6(124) - 216 = -372 , \end{align*} so every set you win scores at most −372-372. A set you lose scores at most 6(124)=7446(124) = 744, by losing 66–00 (each game you win in it only lowers the score, and the 55–77 and 66–77 losses score 118118 and 6161).

You win the match either two sets to love, scoring at most −744-744, or two sets to one, scoring at most −372−372+744=0-372 - 372 + 744 = 0. Either way 31L−53W≤031L - 53W \le 0, and the candidate reaches 00. So the largest share of points you can lose and still win is  106168=5384≈63.1%. \boxed{\ \frac{106}{168} = \frac{53}{84} \approx 63.1\% . \ } Equivalently, the winner can take as little as 36.9%36.9\% of the points.

The computation

The program searches the scorelines directly. It lists every way a game or tiebreak can end (allowing up to three extra deuce pairs), builds every possible points total for a won set and a lost set from the set rules, and combines sets into matches you win. Throughout, for each number of points won it keeps only the largest number of points lost, since no other total can give a higher share. The best match it finds loses 106106 of 168168 points.

from fractions import Fraction

def game_scores(target, extra=3):
    """(winner's points, loser's points) for a game or tiebreak, won by two."""
    return ([(target, k) for k in range(target - 1)]
            + [(target + j, target - 2 + j) for j in range(1, extra + 1)])

def add(A, B):
    """Sums of a pair from A and a pair from B: for each number of points won,
    keep only the most points lost (no other total can lose a bigger share)."""
    best = {}
    for w1, l1 in A:
        for w2, l2 in B:
            best[w1 + w2] = max(best.get(w1 + w2, -1), l1 + l2)
    return set(best.items())

def repeat(menu, k):
    out = {(0, 0)}
    for _ in range(k):
        out = add(out, menu)
    return out

WON = game_scores(4)                      # games you win, as (yours, theirs)
LOST = [(l, w) for w, l in WON]
TB_WON = game_scores(7)
TB_LOST = [(l, w) for w, l in TB_WON]

def sets(you_win):
    g_w, g_l = (WON, LOST) if you_win else (LOST, WON)   # winner's, loser's games
    tb = TB_WON if you_win else TB_LOST
    out = set()
    for k in range(5):                                   # 6-0 up to 6-4
        out |= add(repeat(g_w, 6), repeat(g_l, k))
    out |= add(repeat(g_w, 7), repeat(g_l, 5))           # 7-5
    out |= add(add(repeat(g_w, 6), repeat(g_l, 6)), tb)  # 7-6 on a tiebreak
    return out

won_set, lost_set = sets(True), sets(False)
matches = add(won_set, won_set) | add(add(won_set, won_set), lost_set)
w, l = max(matches, key=lambda p: Fraction(p[1], sum(p)))
print(f"won {w}, lost {l}: share lost = {Fraction(l, w + l)} = {l / (w + l):.4f}")

It prints

won 62, lost 106: share lost = 53/84 = 0.6310

Extra Credit

The two players are evenly matched: each wins any given point with probability 50%50\%, independently of all other points. How likely is it that one of the players loses a strict majority of the points in the match while winning the match itself?

Solution

Follow a single number through the match: the point difference DD, player A’s points minus player B’s. The match winner loses a strict majority of the points exactly when the winner’s difference is negative. By symmetry the answer is twice the probability that A wins the match with D<0D < 0.

The match could in principle last for ever, because of deuce. The observation that removes the difficulty is that deuce does not matter to DD. Once a game reaches three points all, every further pair of points that does not end the game is one point each, and the game ends the moment someone is two ahead. So a game that goes to deuce always ends with a difference of exactly ±2\pm 2, however long it lasts. That makes the effect of each game on DD a finite list. Counting the orders in which the points can fall, A wins a game 44–00 with probability 116\tfrac{1}{16}, 44–11 with probability 432\tfrac{4}{32} and 44–22 with probability 1064\tfrac{10}{64}, and reaches three all with probability 2064\tfrac{20}{64}, after which A wins half the time with a difference of +2+2. So a game changes DD by +4+4, +3+3 or +2+2 with probabilities 116\tfrac{1}{16}, 18\tfrac18 and 516\tfrac{5}{16}, and by −4-4, −3-3, −2-2 with the same probabilities. A tiebreak is the same with seven in place of four: A wins 77–kk for k≤5k \le 5 with probability (6+kk)/27+k\binom{6+k}{k} / 2^{7+k}, and from six all ((126)/212\binom{12}{6}/2^{12}) the difference ends at ±2\pm 2.

Games are independent, so the difference over a set is the sum of the differences of its games. Tracking the games score together with the running difference is now a finite calculation: from each score, each game moves to a new score and a new difference with known probability, until the set ends. The same step, with sets in place of games, carries the calculation through the match. Every probability involved is a whole number divided by a power of two, so the result is an exact fraction. Carrying it out (in the program below) gives  P  =  M2162  ≈  6.267%, \boxed{\ P \;=\; \frac{M}{2^{162}} \;\approx\; 6.267\% , \ } where MM is the 4848-digit whole number M=366 382 889 151 794 439 050 218364 931 384 718 435 785 359 829.\begin{aligned} M = {}& 366\,382\,889\,151\,794\,439\,050\,218 \\ & \quad 364\,931\,384\,718\,435\,785\,359\,829 . \end{aligned}

Where does it come from? A set is won with a negative difference only about 1.4%1.4\% of the time, so in straight sets (two such sets needed) it almost never happens: those matches contribute just 0.066%0.066\%. Nearly all of the answer, 6.20%6.20\%, comes from three-set matches, where the winner’s two sets can be close while the lost set is lopsided, the same shape as the extreme match in the main problem.

The computation

There are two programs. The first carries out the exact calculation just described, with fractions throughout, and checks that the outcomes of the match add up to probability 11. The second ignores all of that reasoning and simply plays half a million matches point by point, deuces and all, counting how often the match winner won fewer points. Its estimate agrees with the exact value to within its sampling error.

from fractions import Fraction
from math import comb
from collections import defaultdict

half = Fraction(1, 2)

def race(target):
    """(A wins?, A's points minus B's) for a game to `target`, won by two."""
    d = defaultdict(Fraction)
    for k in range(target - 1):                    # loser ends with k points
        p = comb(target - 1 + k, k) * half ** (target + k)
        d[(True, target - k)] += p
        d[(False, k - target)] += p
    tie = comb(2 * target - 2, target - 1) * half ** (2 * target - 2)
    d[(True, 2)] += tie / 2                        # from level, ends at +-2
    d[(False, -2)] += tie / 2
    return d

GAME, TIEBREAK = race(4), race(7)

def finish(step, done):
    """Run units (games or sets) from 0-0, tracking the score and difference."""
    out, state = defaultdict(Fraction), {(0, 0, 0): Fraction(1)}
    while state:
        nxt = defaultdict(Fraction)
        for (a, b, diff), p in state.items():
            for (aw, dd), q in step(a, b).items():
                a2, b2 = (a + 1, b) if aw else (a, b + 1)
                if (a, b) == (6, 6):                       # the tiebreak decided it
                    a2, b2 = (7, 6) if aw else (6, 7)
                winner = done(a2, b2)
                if winner is None:
                    nxt[(a2, b2, diff + dd)] += p * q
                else:
                    out[(winner, diff + dd)] += p * q
        state = nxt
    return out

def set_over(a, b):
    if (max(a, b) >= 6 and abs(a - b) >= 2) or max(a, b) == 7:
        return a > b
    return None

SET = finish(lambda a, b: TIEBREAK if (a, b) == (6, 6) else GAME, set_over)
MATCH = finish(lambda a, b: SET, lambda a, b: a > b if max(a, b) == 2 else None)
assert sum(MATCH.values()) == 1
answer = 2 * sum(p for (a_won, d), p in MATCH.items() if a_won and d < 0)
print(answer.numerator, "/ 2 **", answer.denominator.bit_length() - 1)
print(f"= {float(answer):.6f}")

It prints

366382889151794439050218364931384718435785359829 / 2 ** 162
= 0.062672
import random

def play(rng):
    """Play a match point by point; return (A won?, A's points minus B's)."""
    diff = 0
    def unit(target):                     # one game or tiebreak, won by two
        nonlocal diff
        a = b = 0
        while max(a, b) < target or abs(a - b) < 2:
            if rng.random() < 0.5:
                a += 1
            else:
                b += 1
        diff += a - b
        return a > b
    sets_a = sets_b = 0
    while max(sets_a, sets_b) < 2:
        a = b = 0
        while True:
            if (a, b) == (6, 6):
                won = unit(7)
                break
            if unit(4):
                a += 1
            else:
                b += 1
            if (max(a, b) >= 6 and abs(a - b) >= 2) or max(a, b) == 7:
                won = a > b
                break
        sets_a += won
        sets_b += not won
    return sets_a == 2, diff

rng = random.Random(712)
n = 500_000
hits = 0
for _ in range(n):
    a_won, diff = play(rng)
    hits += (diff < 0) if a_won else (diff > 0)
p = hits / n
print(f"{p:.4f} +/- {(p * (1 - p) / n) ** 0.5:.4f}")

It prints

0.0629 +/- 0.0003
Report an error on this page

Reports are stored by Netlify. See the privacy note.