Every position in a finite impartial game under normal play is equivalent to a single Nim heap. Its size is the position’s Grundy number (nim-value):

where is the minimum excluded non-negative integer.

Computing them

int grundy(int s) {
    if (done[s]) return g[s];
    done[s] = true;
    set<int> reachable;
    for (int t : moves(s)) reachable.insert(grundy(t));
    int m = 0;
    while (reachable.count(m)) m++;
    return g[s] = m;
}

For an array-based version, use a boolean “seen” array of size and reset only the entries you touched — clearing a full array per state turns into .

Terminal positions have no moves, so — they are losing, as required.

The sum rule — why this matters

Sprague-Grundy: the Grundy value of a disjoint sum of games is the XOR of their Grundy values.

So a game with independent components has positions but needs only Grundy computations. This is the entire payoff of the theory.

int total = 0;
for (auto& component : components) total ^= grundy(component);
bool firstPlayerWins = (total != 0);

Known Grundy values

GameGrundy value
Nim heap of size
Subtraction game
Subtraction game
Subtraction game period 7:
“Remove any square number”irregular, no closed form known
Lasker’s Nim (remove, or split), , ,
Kayles (remove 1 or 2 adjacent pins)eventually periodic with period 12
Dawson’s chesseventually periodic with period 34
Green Hackenbush (a tree)XOR of branch values (the “colon principle”)
Turning Turtles
Mock Turtles or

Almost every subtraction game has an eventually periodic Grundy sequence — a theorem for finite . So the practical method is: compute the first 100 values, find the period, extrapolate.

The practical recipe

  1. Write a brute-force grundy for small states.
  2. Print the first 30-50 values and look for a pattern.
  3. Common patterns: constant, , periodic, , , or a pattern in binary.
  4. Verify the guessed formula against the brute force on a larger range.
  5. If no pattern emerges, check whether the state space is small enough to precompute, or search OEIS.

This “compute, observe, conjecture, verify” loop is the standard way these problems are solved in contests — deriving the Grundy formula from first principles is usually much harder than spotting it.

Splitting moves

When a move splits one component into several, the resulting position’s value is the XOR of the parts:

// e.g. break a strip of length n into two strips
for (int i = 0; i + 1 < n; i++)
    reachable.insert(grundy(i) ^ grundy(n - 2 - i));

This is the shape of Kayles, Dawson’s chess, and most “cut the row” games. The XOR inside the mex is where the theory does its real work.

What Grundy numbers cannot do

SituationWhy it failsUse instead
Partizan games (different moves per player)Sprague-Grundy assumes impartialityminimax, surreal numbers
Misère playthe sum rule breaksgenus theory; or find the pattern
Games with draws / infinite playnot a finite impartial gameretrograde analysis
Games with chancenot deterministicexpectiminimax
Moves affecting multiple componentsthe sum rule requires independencemodel as one game
Scoring games (not just win/lose)Grundy is about W/L onlygame DP

The last row is worth flagging: if the problem asks “who wins and by how much”, Grundy numbers do not apply — use the advantage-DP from Game DP.

See also: Sprague-Grundy Theorem · Nim · Combinatorial Games