1 module TicTacToe ( 2 Player(..), 3 Fin3(..), 4 Position(..), 5 Move (..), 6 Game, 7 isFreePosition, 8 isValidMove, 9 isValidGame, 10 emptyGame, 11 addMove, 12 moveCount 13 ) 14 where 15 16 import Control.Exception (assert) 17 18 data Player = X | O 19 deriving (Eq, Show, Bounded, Enum) 20 data Fin3 = I1 | I2 | I3 21 deriving (Eq, Show, Bounded, Enum) 22 newtype Position = Position { unPosition :: (Fin3, Fin3) } 23 deriving (Eq, Show) 24 data Move = Move { movePosition :: Position, movePlayer :: Player } 25 deriving (Eq, Show) 26 newtype Game = Game { unGame :: [Move] } 27 deriving (Eq, Show) 28 29 isFreePosition :: Game -> Position -> Bool 30 isFreePosition g p = p `notElem` map movePosition (unGame g) 31 32 isValidMove :: Game -> Move -> Bool 33 isValidMove g m = isFreePosition g (movePosition m) 34 35 isValidGame :: Game -> Bool 36 isValidGame (Game []) = True 37 isValidGame (Game (m:ms)) = isValidMove g m && isValidGame g 38 where g = Game ms 39 40 emptyGame :: Game 41 emptyGame = Game [] 42 43 addMove :: Move -> Game -> Game 44 addMove m g = assert (isValidGame g && isValidMove g m) $ Game (m : unGame g) 45 46 moveCount :: Game -> Int 47 moveCount = length . unGame