The game is implemented as part library and part executable.
The library implements the game logic and the AI and the executable orchestrates the UI. The game is designed in such a way to keep IO at the edges of the implementation.
The library has 100% test coverage and is an instructive example of doing unit testing in Haskell using hspec.
The README for the project goes into more depth about the design of the game. I tried my best to make the code readable and maintainable so that it can also serve pedagogic purposes.
I’d love to hear your feedback on the design and implementation.
P.S. I recently read A Practical Introduction to Freer Monads (Eff) which struck me as a way to defer my use of IO in the executable in order to make it easier to do unit testing. But I’d love to hear other opinions on testing the IO parts.