Pascal and Fermat’s problem of points: dividing the stakes#

Two players stake equal amounts on a game of fair rounds; the first to win a set number of rounds takes the pot. The game is interrupted when player A still needs \(a\) wins and player B needs \(b\). How should the pot be split?

Pascal and Fermat’s answer (1654): imagine the at most \(a + b - 1\) remaining rounds are all played. A takes the pot exactly when A wins at least \(a\) of them, so A’s fair share is

\[P(\text{A wins}) = \sum_{k=a}^{a+b-1} \binom{a+b-1}{k} 2^{-(a+b-1)},\]

a binomial tail probability.

import matplotlib.pyplot as plt
import numpy as np

from mathematicskit.probability import Binomial


def share_of_a(a: int, b: int) -> float:
    """Fair share of the pot for the player who still needs ``a`` wins (opponent needs ``b``)."""
    remaining = Binomial(n=a + b - 1, p=0.5)
    return float(1.0 - remaining.cdf(a - 1))

Pascal’s example: A needs 1 more win, B needs 2#

In his letter of 29 July 1654 Pascal splits a pot of 64 pistoles. With two rounds left to imagine, B only takes the pot by winning both, so A is owed 3/4 of it: 48 pistoles.

a, b = 1, 2
n_left = a + b - 1
remaining = Binomial(n=n_left, p=0.5)
ks = np.arange(n_left + 1)
print(f"A's share = {share_of_a(a, b):.4f} -> {64 * share_of_a(a, b):.0f} of 64 pistoles (Pascal: 48)")

fig, ax = plt.subplots()
colors = ["tab:blue" if k >= a else "tab:red" for k in ks]
ax.bar(ks, remaining.pmf(ks), color=colors)
ax.set_xticks(ks)
ax.set_xlabel(f"rounds won by A among the {n_left} imagined remaining rounds")
ax.set_ylabel("probability")
ax.set_title("Problem of points: blue = A takes the pot, red = B does")
Problem of points: blue = A takes the pot, red = B does
A's share = 0.7500 -> 48 of 64 pistoles (Pascal: 48)

Text(0.5, 1.0, 'Problem of points: blue = A takes the pot, red = B does')

Check by simulating the imagined remaining rounds#

a, b = 3, 5
wins = Binomial(n=a + b - 1, p=0.5).sample(size=200000, seed=0)
print(f"A needs {a}, B needs {b}: exact share {share_of_a(a, b):.4f}, simulated {np.mean(wins >= a):.4f}")
A needs 3, B needs 5: exact share 0.7734, simulated 0.7738

The fair division for every interrupted score#

max_needed = 8
table = np.array([[share_of_a(i, j) for j in range(1, max_needed + 1)] for i in range(1, max_needed + 1)])
fig, ax = plt.subplots()
im = ax.imshow(table, origin="lower", cmap="coolwarm_r", vmin=0.0, vmax=1.0, extent=(0.5, max_needed + 0.5, 0.5, max_needed + 0.5))
ax.set_xlabel("rounds B still needs, $b$")
ax.set_ylabel("rounds A still needs, $a$")
ax.set_title("A's fair share of the stakes")
fig.colorbar(im, ax=ax, label="fraction of the pot owed to A")
print("equal needs give an even split:", all(abs(table[i, i] - 0.5) < 1e-12 for i in range(max_needed)))
A's fair share of the stakes
equal needs give an even split: True

Total running time of the script: (0 minutes 0.072 seconds)

Gallery generated by Sphinx-Gallery