Guest User

Untitled

a guest
Jul 19th, 2018
85
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.93 KB | None | 0 0
  1. module Main
  2. where
  3.  
  4. import Data.Maybe (isNothing, fromJust)
  5. import Data.List (intercalate)
  6. import Char (toUpper)
  7. import System.IO (hFlush, stdout)
  8.  
  9. data Move = O | X
  10. deriving (Eq, Show, Enum, Ord)
  11. type Position = (Char, Int)
  12. data BoardMove = BoardMove
  13. { bMove :: Maybe Move, bPos :: Position }
  14. deriving (Eq, Show)
  15. type Board = [BoardMove]
  16. type InvalidMove = String
  17.  
  18. bsize :: Int
  19. bsize = 3
  20.  
  21. coord = (['A'..], [1..])
  22.  
  23. empty :: Int -> Board
  24. empty size = do
  25. x <- take size (fst coord)
  26. y <- take size (snd coord)
  27. return $ BoardMove Nothing (x,y)
  28.  
  29. find :: Position -> Board -> Maybe BoardMove
  30. find pos [] = Nothing
  31. find pos (x:xs) = if eqPos x then Just x else find pos xs
  32. where eqPos (BoardMove _ p) = p == pos
  33.  
  34. move :: BoardMove -> Board -> Either InvalidMove Board
  35. move (BoardMove _ (c,r)) [] =
  36. Left $ "Could not make a move for given position " ++ [c] ++ (show r)
  37. move bm@(BoardMove nmov npos) (x:xs)
  38. | findMove x = Right $ bm:xs
  39. | otherwise =
  40. case move bm xs of
  41. Right r -> Right $ x:r
  42. err -> err
  43. where findMove (BoardMove m p) =
  44. p == npos && isNothing m && nmov /= Nothing
  45.  
  46. win :: BoardMove -> Board -> Bool
  47. win (BoardMove Nothing _) _ = False
  48. win (BoardMove m (c,r)) b = row || col || diag' cb || diag' (reverse cb)
  49. where row = length
  50. (filter (\(BoardMove m2 (_,r2)) ->
  51. m2 == m && r2 == r) b) == bsize
  52. col = length
  53. (filter (\(BoardMove m2 (c2,_)) ->
  54. m2 == m && c2 == c) b) == bsize
  55. diag' xss = all (\(BoardMove m2 _) ->
  56. m2 == m) $ diag xss
  57. cb = chop bsize b
  58.  
  59. draw :: BoardMove -> Board -> Bool
  60. draw bm b = not (any (isNothing . bMove) b)
  61. && not (win bm b)
  62.  
  63. printBoard :: Board -> String
  64. printBoard b = intercalate "\n" $
  65. map (\row-> [(fst . bPos) (row !! 0)] ++ ") | " ++
  66. (intercalate " | "
  67. $ map (\bm-> maybe " " show $ bMove bm) row)
  68. ++ " |")
  69. (chop bsize b)
  70.  
  71. chop :: Int -> [a] -> [[a]]
  72. chop n [] = []
  73. chop n xs = take n xs : chop n (drop n xs)
  74.  
  75. diag :: [[a]] -> [a]
  76. diag xss = [xss !! n !! n | n <- [0 .. length xss - 1]]
  77.  
  78. main = do
  79. putStrLn "Starting new game..."
  80. putStrLn "Type 'quit' to exit game"
  81. let newBoard = empty bsize
  82. in do (putStrLn . (\s->"\n"++s++"\n") . printBoard) newBoard
  83. gameloop Nothing newBoard
  84.  
  85. gameloop prevMove board = do
  86. let currPlayer = maybe X (\(BoardMove mv _) ->
  87. case mv of
  88. Just X -> O
  89. Just O -> X) prevMove
  90. putStr $ "Player '" ++ (show currPlayer) ++ "': "
  91. hFlush stdout
  92. playerMove <- getLine
  93. case (playerMove, (map toUpper playerMove) `elem` allCoord) of
  94. ("quit", _) ->
  95. putStrLn "Goodbye!"
  96. (_, False) -> do
  97. putStrLn $ "Possible options: " ++ intercalate ", " allCoord
  98. gameloop prevMove board
  99. otherwise -> do
  100. let pos = (toUpper $ playerMove !! 0,
  101. read [(playerMove !! 1)] :: Int)
  102. currMove = BoardMove (Just currPlayer) pos
  103. currBoard = move currMove board
  104. either putStrLn (putStrLn . (\s->"\n"++s++"\n") . printBoard) currBoard
  105. case currBoard of
  106. Right r -> if win currMove r
  107. then do putStrLn $ "Player '"
  108. ++ (show currPlayer) ++"' wins!"
  109. main
  110. else if draw currMove r
  111. then do putStrLn $ "It's a draw!"
  112. main
  113. else gameloop (Just currMove) r
  114. Left err -> gameloop prevMove board
  115. where allCoord = [[x] ++ show y | x <- take bsize (fst coord),
  116. y <- take bsize (snd coord)]
Add Comment
Please, Sign In to add comment