Checkers (Sans AI) is Ready!
This morning, I completed the “plumbing” for checkers. Specifically, with all the game mechanics in place, I now have a framework that will allow two “players” (a red player and a black player) to play against each other ad infinitum using either the same or different models. In order to get everything up and running and test the game itself, I threw together a bare bones “model” that does nothing but generate random moves. When I first completed it, when I ran the main program, it played games indefinitely at about 1 per second on my Mac, and maybe 3 per second on the desktop PC that I use for data/AI heavy lifting. For each game, it reports back the winner of the game, the number of pieces left on each side, the number of moves each side made, and the number of invalid moves each model came up with before landing on a valid move (a lot).
Shortly after completing that, I made two small, but very important improvements. First, I had completely forgotten to build in the rule that jumps are mandatory for a player if available. Making that update shortened the games a lot. Just from watching the numbers fly by, I’d estimate that before the “jump rule” the at least half of games were taking 100 or more moves for each side. With the rule in place, I rarely ever see a game go to 100 moves or more. That change also approximately doubles the speed. I can turn it on or off by specifying that on launch because I figure if I can actually design a worthy AI chessbot, I’ll want to put it online and allow folks to play it. And I know that some people don’t play with that rule, so I’ll need to train one model with the rule on, and another with the rule off.
The other change was not calling the routine that checks for legal moves every time it needs to know within a turn. Since both the game and the player are relying on a random number generator that assumes every move for every piece is legal, it has to check a lot, and generate a new number when the previous one was illegal. In fact for every legal move that the game and player accepts, there are about 10-20 that are rejected. They’re rejected by checking the move against legal moves in the current board position. And the algorithm to check, while not overwhelmingly complex, is not a trivial one. What I had been doing was calling that routine every time the check needed to occur in a single turn, even though the answer could never change until the player actually made a move. So I updated it to just load the legal moves array into a variable at the start of the turn and then compare against that. After making that update, the desktop PC is now running over 20 entire games per second. That’s very pleasing.