Chapter 87
Can You Make The Fidget Spinner Go Backwards?
A thousand players each hold a random board of distinct pictures drawn from a -card deck. Cards are drawn one at a time, and a player wins on completing any full row, full column, the four corners, or any block ( winning patterns). After four cards there is no winner. What is the probability that exactly one player wins when the fifth card is drawn?
Solution
This is a conditional probability tied to the shared sequence of drawn cards. Draw five cards; the first four leave no winner, and we ask how often the fifth card produces exactly one. Each of the thousand boards is an independent random -subset, so given the five drawn cards a board wins only if some one of its patterns is fully covered. The dependence on the common draw and the size of the field ( boards) makes a clean formula awkward, so the honest tool is direct simulation: deal the five cards, discard any deal in which someone already won by the fourth, and among the rest measure how often the fifth card crowns precisely one winner. The result is A single winner on the fifth card is the most common interesting outcome; ties (two or more winning together) and no-winner are the remaining cases.
The computation
Deal five cards to a thousand random boards, mark each board’s win status by testing all patterns against the drawn set, keep only deals with no winner after four cards, and record how often exactly one board wins after five.
import numpy as np
rng = np.random.default_rng(0)
patterns = np.array([[0,1,2,3],[4,5,6,7],[8,9,10,11],[12,13,14,15],
[0,4,8,12],[1,5,9,13],[2,6,10,14],[3,7,11,15],[0,3,12,15],
[0,1,4,5],[1,2,5,6],[2,3,6,7],[4,5,8,9],[5,6,9,10],
[6,7,10,11],[8,9,12,13],[9,10,13,14],[10,11,14,15]])
def trial(players=1000):
boards = np.argsort(rng.random((players, 54)), axis=1)[:, :16]
draw = rng.permutation(54)[:5]
def winners(k):
marked = np.isin(boards, draw[:k]) # which board cells are drawn
return sum(marked[:, p].all(1) for p in patterns) > 0
if winners(4).any(): return None # someone already won
return int(winners(5).sum())
res = [r for _ in range(40_000) if (r := trial()) is not None]
print(np.mean([w == 1 for w in res])) # ~0.18