Every position of a finite impartial game under normal play is equivalent to a single Nim heap. Its size is the Grundy number (nim-value)
where mex is the minimum excluded non-negative integer; terminal positions get . Then iff is losing, and the value of a disjoint sum (a move changes exactly one component) is the XOR:
A game with independent components has positions but needs only Grundy computations. To find a winning move, pick a component and a move in it that turns the total XOR into 0 (as in Nim). Cost: for all values, to combine.
Nimber is the formal name (from Conway’s combinatorial game theory) for a Grundy value viewed as an element of an algebraic structure rather than just an integer: nimbers under “nimber addition” (defined as XOR, matching the disjoint-sum rule above) and a separate “nimber multiplication” (a more exotic operation, computed recursively via ) form a field — this lets a game be analysed as an algebraic value, which is how Hackenbush/Nim-like sums get combined in deeper combinatorial-game-theory arguments. Nimber multiplication itself is essentially never needed directly in CP (every problem in this repo’s scope only uses nimber addition, i.e. plain XOR); it is cited here, not derived, purely so the term “nimber” is not an unexplained gap.
// Grundy values of an acyclic game graph given in topological order of "moves go to smaller ids" (or any DAG order).
vector<int> grundyAll(const vector<vector<int>>& moves, const vector<int>& order) { // order: sinks first
int n = sz(moves); vector<int> g(n, 0), seen(n + 2, -1);
for (int s : order) {
for (int t : moves[s]) if (g[t] <= n) seen[g[t]] = s; // mark with the state id: no clearing
int m = 0; while (seen[m] == s) m++;
g[s] = m;
}
return g;
}
// Row games ("octal-like"): a row of n pins, a move removes r in R adjacent pins anywhere, possibly splitting the row.
// Kayles: R = {1, 2}; Dawson's Kayles: R = {2} (Dawson's chess with n pawns = Dawson's Kayles with n + 1 pins).
vector<int> rowGameGrundy(int N, const vector<int>& R) {
vector<int> g(N + 1, 0), seen(2 * N + 4, -1);
for (int n = 1; n <= N; n++) {
for (int r : R) for (int a = 0; a + r <= n; a++) seen[g[a] ^ g[n - r - a]] = n;
int m = 0; while (seen[m] == n) m++;
g[n] = m;
}
return g;
}
// Smallest period p (with start n0) such that g[n + p] = g[n] holds on [n0, 2 n0 + p + t), which by the
// Guy-Smith periodicity theorem proves periodicity forever (t = largest number of pins removed). {-1,-1} if none.
pair<int, int> certifiedPeriod(const vector<int>& g, int t, int maxP) {
int N = sz(g) - 1;
for (int p = 1; p <= maxP; p++) {
int n0 = N - p;
while (n0 > 0 && g[n0 - 1 + p] == g[n0 - 1]) n0--;
if (2 * n0 + p + t <= N - p) return {n0, p};
}
return {-1, -1};
}
vector<int> subtractionGrundy(int N, const vector<int>& S) { // remove s in S stones from one heap
vector<int> g(N + 1, 0), seen(sz(S) + 2, -1);
for (int n = 1; n <= N; n++) {
for (int s : S) if (s <= n && g[n - s] <= sz(S)) seen[g[n - s]] = n;
int m = 0; while (seen[m] == n) m++;
g[n] = m;
}
return g;
}
int mockTurtles(ll i) { return int(2 * i + (__builtin_popcountll(i) % 2 == 0)); } // i-th odious numberKnown values
| Game | Grundy value |
|---|---|
| Nim heap of size | |
| subtraction game | (so : ) |
| period 7: | |
| period 5: | |
| any finite | eventually periodic (theorem below) |
| = all squares, all primes | irregular, no closed form known |
| Lasker’s Nim (remove, or split a heap in two) | , , , |
| Kayles (remove 1 or 2 adjacent pins) | period 12 from on: |
| Dawson’s Kayles (remove exactly 2 adjacent pins) | period 34 from on |
| Grundy’s game (split a heap into two unequal heaps) | computed to huge , no period found |
| Green Hackenbush on a tree | : Hackenbush |
| Turning Turtles (turn one coin HT, optionally one coin to its left) | single head at position (from 1): , i.e. plain Nim |
| Mock Turtles (turn up to 3 coins, the rightmost HT) | single head at position (from 0): the -th odious number or |
| coin-turning games in general | a position is the XOR of its single-head values |
Practical recipe: write a brute-force grundy for small states, print the first 30–50 values, guess the pattern (constant, , periodic, , , a binary pattern), verify against the brute force on a larger range, and if nothing appears, precompute or search OEIS. For splitting moves the reachable set contains XORs of the parts, g[i] ^ g[n - r - i]: this XOR inside the mex is where the theory does its real work (Kayles, Dawson’s chess, “cut the row” games).
Proof: the Sprague–Grundy theorem
Write if and have the same winner for every game . Claim: every position satisfies , the Nim heap of size . Induction on the (well-founded) game order. By the mex definition the options of include, for every , a position of value , which by induction is equivalent to ; and no option has value . Consider against ; it suffices to show that is a second-player win. Indeed, adding a second-player win never changes the winner of a game (whoever wins keeps playing there and answers every move in by ‘s second-player strategy), and is a second-player win (mirror), so . In : if the first player moves the heap to , , the second player moves to an option of value , giving with , a second-player win by induction. If the first player moves to an option with : if , reply by moving the heap to ; if , has an option of value (mex), move there. Either way the second player restores a position of the form , and the game is finite.
Sums. Each component is equivalent to a Nim heap, so the sum is equivalent to a Nim position, whose value is the XOR of the heap sizes (Bouton). In particular a sum is losing iff the XOR is 0.
Proof: eventual periodicity (subtraction games and the Guy–Smith certificate)
Finite subtraction sets. With finite, is the mex of at most values, so . The value depends only on the window , which takes at most values. Some window repeats, at and , and from then on the sequence repeats with period (the recurrence is deterministic). The code’s
seenarray is indexed by values .Row games (Guy–Smith). Suppose moves remove at most pins and for all in . Take and assume the relation for all . An option of removes pins and leaves rows with , so one of them, say , is at least , and with ; hence is the value of the option of . Conversely an option of has , so one part, say , is at least and , giving an option of with the same value. Equal option sets give .
certifiedPeriodchecks exactly this window; it certifies Kayles (period 12 from 71) and Dawson’s Kayles (period 34 from 53).
Proof: Lasker's Nim
Claim for : with , and precisely , , , . Induction on . Removals reach every ; by induction is when , and when . Splits () give , whose residue mod 4 is . For : residue pairs give and , so splits are and miss : . For : pairs give : splits miss , . For : pairs give ; the split gives , and no option equals : . For : the value is missing from removals, and splits give residues , , , never : .
Proof: coin-turning games are sums of single heads
In a coin-turning game a move turns over a set of coins whose rightmost one goes from heads to tails, and the allowed sets do not depend on the other coins. Identify a position with the sum of single-head games, one per head. A move at a head is the same in both: remove component , and toggle the coins to its left; a toggled tail becomes a new single-head component, and a toggled head becomes a second component at . Two equal components sum to a second-player win (, mirror strategy), so adding a second copy of the head- game is equivalent to removing the first. Hence the position and the sum always have equal values, and the value is the XOR of single-head values. Checked by exhaustive search over all positions of up to 12 coins for Turning Turtles () and Mock Turtles (odious numbers).
What Grundy numbers cannot do
| Situation | Why it fails | Use instead |
|---|---|---|
| partizan games | Sprague–Grundy needs identical move sets | minimax, game values: Hackenbush and Surreal Numbers |
| misère play | the sum rule breaks | misère Nim, genus theory, or find the pattern |
| draws / infinite play | not a finite game | generalized Sprague–Grundy, retrograde analysis: Loopy Games |
| chance | not deterministic | expectiminimax |
| moves touching several components | the sum rule needs independence | model as one game |
| scores (“who wins and by how much”) | Grundy is about win/lose only | advantage DP: Game DP |
Applications: Nim itself (heap = value), Wythoff’s game (with an extra move type), turning and coin games, Green Hackenbush, and almost every multi-pile contest game problem.