In this post I will present my Haskell implementation of the classic Tic-tac-toe game.
I call it xo-haskell.
I won't go too much into the details but instead I'll try to give a 10,000 foot view of the game's overall design.
The star of the library is the Game module. It encapsulates and enforces Tic-tac-toe's game logic.
For e.g. Let's say we want to start a game where O plays first. We can do the following:
>>> import XO.Mark >>> import XO.Game as Game >>> let game0 = Game.new O
game0 is a Game where O plays first.
To actually play you call the
play function with the position you want to mark.
>>> let Right game1 = Game.play (0,0) game0 >>> game1 o........; x
You don't pass X or O to the function since whose turn it is is managed behind the scenes. Doing it that way ensures that play always alternates between X and O.
You can't play out of bounds or in a marked position.
>>> let Left error = Game.play (3,3) game1 >>> error OutOfBounds
That's enforced here.
>>> let Left error = Game.play (0,0) game1 >>> error Unavailable
And that's enforced here.
All interactions with the outside world, IO, happens in the executable.
The key thing to notice is how straightforward the implementation of each orchestrator becomes when the game logic is handled as a separate concern.
- If you've read LYAH or Haskell Book but you're still having problems designing and implementing complete Haskell applications.
- To learn how to unit test Haskell code.
- To learn how to document Haskell code.
- To learn how to design a library for a turn-based game.
- To learn how to parse command-line options.
Programming a well designed Tic-tac-toe game in any language (much less Haskell) seems to be a non-trivial problem. I hope this post and the source code for xo-haskell shows you a way that it may be done.
What do you think about the design and the implementation? I'd love to get your thoughts on how it could be improved.