Omnicorn Pork Association

Checkers game-over in Haskell

The programming subreddit recently had a discussion about testing a checkers board for game-over. I wondered how specifying the rules for legal moves would look with Haskell’s pattern matching, and this post is a study of that technique. In fact, you can run yourself. Copy-and-paste the post body to a file named Checkers.lhs to get a working program!

The game is American checkers or English draughts, played on an eight–by–eight checkerboard, of all surfaces.

The OP on reddit chose white and blue for the sides’ colors, and above we have more–or–less declarative rules for legal white moves. A pawn or king (w and W respectively) can move to an empty space before it. Kings are special in that they can move backwards. The list ends with legal jumps, and everything else is invalid.

The code is repetitive, but I’ll clean that up later.

An immediate problem is the patterns are linear, but all legal moves in checkers are along diagonals. I kicked around ideas such as using IArray or nasty double-applications of !!. Then I realized I could rotate the board by 45° with a shear, a transposition, and removal of placeholders.

To wring out the duplication in the code for each side’s moves, I considered using Template Haskell—a cousin of Lisp macros for Haskell. I decided to push lexical closures as far as I could, and the result is below.

The code in count (notice the view pattern?) is a skeleton to be customized for the blue side and the white side, and it distills the repeated code. The definition of sideCanMove generalizes the rules for legal moves on either side. We have to reverse the diagonals to make them usable on the white side.

To get both sets of diagonals, the only difference is how to shear the board: bottom-away for positive slopes and top-away for negative.

Finally come the tests that I added as I went. To factor out duplication, each board becomes two testcases. The first is as–is, and the same condition should hold for the other side. See the definition of invert in the where clause.

I had hoped for a more elegant result, but it was an interesting exercise and a fun problem!