This is a good example for a short discussion on dynamic programming. DP solutions should be very formulaic and clear. It helps to practice some structure around your implementation to make coming up with a solution easier. You will almost always have certain key elements in your dp-implementation:
The table is necessary to store the result of each call when it completes the first time, and retrieved from memory each time thereafter.Recurrence relation, defining the sequence as a recursive function of itself and some stop condition or base case. Usually you want the arguments of your function to relate directly to the indices your memoization table.
For example, if we are computing the fibonacci sequence with a top-down memoization strategy, our recurrence is $\t{fib(n) = fib(n-1) + fib(n-2)}$ , and our memoization table is $\t{int dp[MAX_N];}$ where $\t{dp[i] = fib(i)}$ once computed.
Formulating the recurrence relation is the only challenging part of dynamic programming problems. But once you have the recurrence defined the rest should be so routine that it's easy. You should be tell me, in plain English, what your DP function does. By that, I mean if your DP function is:
then your explanation should be "$\t{minimax_nim(n, is_first_turn)}$ is the winner of the Nim game when there is n items left and it is player 1's turn next if $\t{is_first_turn}$ is true, otherwise player 2's turn next".