Nim

(also known as the Marienbad game)

Initially, n ≥ 2 chips are on a table.   Two players alternate taking some chips off.   The player who takes the last chip wins.

Rules:
    The first player takes i, where 1 ≤ in-1.
    Thereafter, if a player takes p then the next play is q, where 1 ≤ q ≤ 2p.

There are no draws possible, as each move reduces the numebr of reminaing chips.   The question is how to characterize those values of n for which the first player cam ensure a win.

A position in this game is not specified merely by the number of chips on the table, but also by the upper limit on the next move.

The initial position = <n, n-1>
A general move:   <i, j>(1 ≤ kj) <i-k, min{2k, i-k}>

Receiving position <0,0> means that the player loses.

Each position can be characterized as winning or losing.   Winning means that, despite what your opponent may do, if you are clever then you will win.   Losing means that, unless your opponent should do something stupid, you will lose.

The following are three functionally equivalent procedures that determine whether <n, p> is winning, and which differ by their time complexity.

Recursion, suffers from recalculating some values many times.

    Rec(i,j)
       ans := LOSE
       for k := 1 to j do
          if Rec(i-k, min{2k,i-k})=LOSE then
             ans := WIN
             break
       return ans

Dynamic programming, suffers from calculating some values that are never needed.

    Dyn(n,p)
       G[0,0] := LOSE
       for i := 1 to n do
          for j := 1 to i do
             G[i,j] := LOSE
             for k := 1 to j do
                if G[i-k, min{2k,i-k}]=LOSE then
                   G[i,j] := WIN
                   break
       return G[n,p]

Recursion with memory function, takes the advantages and avoids the disadvantages.

    Nim(i,j)
       initialize G[*,*] to Unknown
           /** can avoid O(ij) time at cost of extra space **/
       return Nim1(i,j)

    Nim1(i,j)
       if G[i,j] is not Unknown then
           return G[i,j]
       for k := 1 to j do
          if Nim1(i-k, min{2k,i-k})=LOSE then
             G[i,j] := WIN
             return WIN
       G[i,j] := LOSE
       return LOSE


Dan Hirschberg
Last modified: Oct 28, 2003