tictactoe3d 0.1.0.2 → 0.1.0.3
raw patch · 3 files changed
+120/−46 lines, 3 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- src/Game/TicTacToe3D/TicTacToe3D.hs +86/−35
- src/Game/TicTacToe3D/Vector3.hs +33/−10
- tictactoe3d.cabal +1/−1
src/Game/TicTacToe3D/TicTacToe3D.hs view
@@ -1,4 +1,6 @@--- Defines a state machine of 3D Tic-Tac-Toe. +{-| + Defines a state machine of 3D Tic-Tac-Toe. +-} module Game.TicTacToe3D.TicTacToe3D ( Team, Issue, @@ -17,42 +19,59 @@ import Data.Tuple.Homogenous import Game.TicTacToe3D.Vector3 as V - -- [1, 2, 3, 4, 5] -> [(1, 5), (2, 4)] + {-| + Restructures a list. + + >>> collapse [1, 2, 3, 4, 5] + [(1, 5), (2, 4)] + -} collapse :: [a] -> [(a, a)] collapse ns = take (halfLen ns) (collapse' ns) where halfLen ms = length ms `quot` 2 collapse' ms = zip ms (reverse ms) - -- In the specified dimension, - -- generates all the possible directions, - -- and pairs up every two of them that face to each other. + {-| + In the specified dimension, + generates all the possible directions, + and pairs up every two of them that face to each other. + -} directions :: Int -> [([Int], [Int])] directions i = collapse $ allDirections where allDirections = replicateM i [-1, 0, 1] - -- Simplifies `directions 3`. + {-| + Simplifies + + > directions 3 + -} directions3 :: [Tuple2 I3] directions3 = f <$> directions 3 where f t = g <$> Tuple2 t where g [x, y, z] = (x, y, z) - -- Retrieves a line to every direction from the given point. + {-| + Retrieves a line to every direction from the given point. + -} explode :: I3 -> [Tuple2 [I3]] explode c = (walk c <$>) <$> directions3 where walk h i = let j = add h i in j : walk j i where add (h, i, j) (k, l, m) = (h + k, i + l, j + m) - -- Checks if the given point is inside of - -- the specified area in every three dimension. + {-| + Checks if the given point is inside of + the specified area in every three dimension. + -} withinC :: Int -> Int -> I3 -> Bool withinC min max c = F.all f $ Tuple3 c where f n = min <= n && n < max - -- Retrieves all the possible lines that - -- intersect at the given point. All those - -- lines are within the area - -- from 0 to the specified number. + {-| + Retrieves all the possible lines that + intersect at the given point. All those + lines are within the area + from 0 to the specified number. + -} explode' :: Int -> I3 -> [[I3]] explode' len crd = catMaybes $ do Tuple2 (fs, bs) <- explode crd @@ -60,45 +79,67 @@ pick = takeWhile $ withinC 0 len return $ if length line == len then Just line else Nothing - -- Represents a team. + {-| + Represents a team. + -} type Team = Bool - -- Represents a state of one point in a board; - -- owned by either team or empty. + {-| + Represents a state of one point in a board; + owned by either team or empty. + -} type Issue = Maybe Team - -- Represents a tic-tac-toe board with its side length + {-| + Represents a tic-tac-toe board with its side length. + -} type Board = (Int, V3 Issue) - -- B B B -> B - -- B B R -> D - -- B B - -> D + {-| + Folds a list of 'Issue'. + + > foldI [B, B, B] = B + > foldI [B, B, R] = D + > foldI [B, B, _] = D + -} foldI :: [Issue] -> Issue foldI [] = Nothing foldI (x:xs) = F.foldr add x xs where add m n = if m == n then m else Nothing -- not Monoid; mappend mempty x /= x - -- firstJust [Nothing, Just 1 , Nothing] = Just 1 - -- firstJust [Nothing, Nothing, Nothing] = Nothing + {-| + Retrieves the first 'Just' element in a given structure, + or 'Nothing' if not found any. + + > firstJust [Nothing, Just 1 , Nothing] = Just 1 + > firstJust [Nothing, Nothing, Nothing] = Nothing + -} firstJust :: (Foldable f) => f (Maybe a) -> Maybe a firstJust ms = join $ F.find isJust ms - -- Retrieves the winner and the owned line. - -- Nothing if the game has not ended yet. + {-| + Retrieves the winner and the owned line. + Nothing if the game has not ended yet. + -} check :: Board -> I3 -> Maybe ([I3], Team) check (i, v) c = firstJust $ do l <- explode' i c let j = foldI $ (v V.!) <$> l return $ (,) l <$> j - -- Represents a result of one team's action. + {-| + Represents a result of one team's action. + -} type Result = Maybe (Either [I3] Board) - -- Makes the given team play the specified square. - -- Just Left [I3] → The team has won. - -- Just Right Board → The game goes on. - -- Nothing → The specified square is not playable. + {-| + Makes the given team play the specified square. + + > Just Left [I3] -- The team has won. + > Just Right Board -- The game goes on. + > Nothing -- The specified square is not playable. + -} play :: Board -> Team -> I3 -> Result play (l, v) t c | v V.! c /= Nothing = Nothing @@ -108,25 +149,35 @@ Just (cs, _) -> Left cs Nothing -> Right new - -- Initializes a board with the given values. + {-| + Initializes a board with the given values. + -} initBoard :: Int -> (I3 -> Issue) -> Board initBoard i f = (,) i $ V.init i f - -- Represents a state of a tic-tac-toe game. - -- `Done` represents a game that has finished. + {-| + Represents a state of a tic-tac-toe game. + 'Done' represents a game that has finished. + -} data Game = Game Board Team | Done Team [I3] - -- An initialized state of a game. + {-| + An initialized state of a game. + -} newGame :: Game newGame = Game newBoard True where newBoard = (initBoard 3 $ const Nothing) - -- Retrieves True if the given game has finished, otherwise False. + {-| + Retrieves whether the given game has finished or not. + -} done :: Game -> Bool done (Done _ _) = True done _ = False - -- Makes the current team play at the specified square. + {-| + Lets the current team play at the specified square. + -} playGame :: Int -> Game -> Game playGame _ g @ (Done _ _) = g playGame c g @ (Game b t) =
src/Game/TicTacToe3D/Vector3.hs view
@@ -1,40 +1,63 @@--- Defines a 3-layered Vector and relative utilties. +{-| + Defines a 3-layered Vector and relative utilties. +-} module Game.TicTacToe3D.Vector3 where import Data.List (unfoldr) import Data.Vector (Vector) import qualified Data.Vector as V + {-| + Represents a 3-layered structure. + -} type Dim3 a b = a (a (a b)) - -- Represents a 3-layered vector. + {-| + Represents a 3-layered vector. + -} type V3 a = Dim3 Vector a - -- Represents an index of a 3-layered vector. + {-| + Represents an index of a 3-layered vector. + -} type I3 = (Int, Int, Int) - -- base 2 10 = [0, 1, 0, 1] + {-| + >>> base 2 10 + [0, 1, 0, 1] + -} base :: Int -> Int -> [Int] base i n = unfoldr f n ++ repeat 0 where f b = if b /= 0 then Just (pair b i) else Nothing where pair n i = (n `mod` i, n `div` i) - -- i3 1 = (1, 0, 0) - -- i3 26 = (1, 1, 1) + {-| + >>> i3 1 + (1, 0, 0) + + >>> i3 26 + (1, 1, 1) + -} i3 :: Int -> I3 i3 i = t $ base 3 i where t (x:y:z:_) = (x, y, z) - -- Retrieves the specified location's element. + {-| + Retrieves the specified location's element. + -} (!) :: V3 a -> I3 -> a v ! (x, y, z) = v V.! x V.! y V.! z - -- Replaces the specified location's element - -- and retrieves the updated vector. + {-| + Replaces the specified location's element + and retrieves the updated vector. + -} (//) ::V3 a -> (I3, a) -> V3 a v // ((x, y, z), n) = (setf x $ setf y $ setv z n) v where setf i f y = setv i (f $ y V.! i) y setv i m y = y V.// [(i, m)] - -- Initializes with the given values. + {-| + Initializes a vector with the given values. + -} init :: Int -> (I3 -> a) -> V3 a init i f = V.generate i $ \x ->
tictactoe3d.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/ name: tictactoe3d -version: 0.1.0.2 +version: 0.1.0.3 synopsis: 3D Tic-Tac-Toe game description: Defines 3D Tic-Tac-Toe game logic and state machines. homepage: https://github.com/ryo0ka/tictactoe3d