Library · The Fiddler: Solutions · Chapter 151
Can You Survive Another Squid Game?
The final players of a Squid Game stand in a circle, numbered to clockwise. Contestant is eliminated first. Then the contestant two places clockwise from where stood, contestant , is eliminated, then contestant , and so on round the circle, which closes up after every elimination. So after contestant goes, the next to go is , now two places clockwise from where stood. This continues until one contestant is left. What is the winner’s number?
The Fiddler, Zach Wissner-Gross, July 21, 2023(original post)
The official solution appeared in the post of July 28, 2023 and gives contestant , and for the Extra Credit contestant , with probability . Both agree with the answers below.
Solution
This is the Josephus problem with every second person removed, and it yields to one observation: a full lap round the circle halves the problem.
With players, the first lap removes , every even number. That leaves the ten odd numbers , and the count resumes from where stood, so the next to go is , the second of the survivors. That is exactly the original game played on ten people, with the th person in the new circle wearing the number . Writing for the position of the winner in a circle of , An odd circle, , works the same way with one extra step. The lap removes , and the next count skips and removes . The survivors then play the game afresh, the count starting just after , so the th of them wears , and With these two rules finish the job in four steps: Unwinding the rules gives the classical closed form. If with , the winner is : here and . In words, once people have been removed the circle has a power of two left, and from then on the person about to start each lap, here number , is never touched.
The computation
The check simply plays the game on a list, removing contestants one at a time. It is written for any sequence of steps, so the Extra Credit can reuse it.
from fractions import Fraction
from itertools import product
def play(steps, n=20):
"""Play the game: each step moves that many places
clockwise from the last elimination and removes the
contestant there. Returns the winner."""
circle = list(range(1, n + 1))
gap = 0 # index of the place just vacated
for s in steps:
k = (gap + s - 1) % len(circle)
circle.pop(k)
gap = k % len(circle) if circle else 0
if len(circle) == 1:
break
return circle[0]
print("always two places: winner", play([2]*19))
It prints
always two places: winner 9
Extra Credit
Run the game again, but now each move goes two or three places clockwise, chosen at random with equal chances and independently each time. Which contestant is most likely to win?
Solution
The halving trick is gone, because a random step breaks the regular lap. What survives is the idea of relabelling the circle after each elimination.
Describe a circle of people by numbering them clockwise starting just after the place where the last elimination happened. A move of places removes the person numbered (counting round again if , so in a circle of two a move of three removes person ). The circle that remains has people, and renumbering it from just after the removed person sends old number to new number if , and to if .
Write for that new number. If is the chance that the person numbered in a circle of wins, then and with a term counted as zero when that move removes . The start of the puzzle is exactly this numbering, with contestant numbered , so the answer is the largest of .
The first few circles show how it goes. In a circle of two, a move of two removes person and a move of three removes person , so each wins with chance . In a circle of three, person survives either move and then stands in a circle of two, winning with chance ; persons and each survive one move of the two and win with chance . Each step of the recursion has denominators that double, so after eliminations every chance is a whole number over .
Running the recursion up to , by hand in principle and by computer in practice, gives the chart below. The chances climb steadily through the late teens and peak at contestant : The value comes from computation rather than a formula; the recursion is what makes it exact. The neighbours are close behind, at and at , while and , the only ones who can go first, are the least likely to win.
The computation
The check does not use the recursion. There are only equally likely sequences of moves, so it plays every one of them with the play function above and counts the winners.
wins = [0]*21
for steps in product((2, 3), repeat=19): # all 2^19 runs
wins[play(steps)] += 1
best = max(range(1, 21), key=lambda c: wins[c])
p = Fraction(wins[best], 2**19)
print("most likely winner:", best)
print(f"with probability {p} = {float(p):.4f}")
It prints
most likely winner: 18
with probability 35531/524288 = 0.0678