Your code is now quite complex. How do you know it is right? Testing and debugging is one of the hardest jobs in building an adversary. The code may pick a wrong move for some reason that you cannot understand. The code may crash because you failed to think of a hard case.
Back at the beginning, I had you build a method to read in a state. Now, build some test states and run your code on them. See how deep the search gets and whether a good-looking move is chosen. Build states to try strange cases, like when a Pawn reaches the end and becomes a Queen.
Modify your program to play against itself, printing the state after each move. Run this on the states you have built. Does the program stop when it should? Do the moves look OK?
Many computer game tournaments are won not by the best program, but by the most solid. You cannot afford to lose a game because your program crashes, makes an illegal move, or makes an awful move. Check carefully.
Missed Opportunity: One good way to check your program is to make sure that the final version of negamax—the one with do-undo, alpha-beta, etc—always gives the same answer as the original version of negamax if they search to the same depth. We did not take time to do this here.prev index