Note
Go to the end to download the full example code.
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")

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 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)))

equal needs give an even split: True
Total running time of the script: (0 minutes 0.072 seconds)