-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathtictactoe.hs
98 lines (85 loc) · 2.87 KB
/
tictactoe.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
{-# LANGUAGE FlexibleInstances,OverlappingInstances #-}
import Control.Monad
import System.Exit
--import Data.List.Split
import Data.Char (isDigit)
data Player = X | O deriving (Eq)
data GameResult = GameResult Player | Tie | Unknown
type Board = [[Maybe Player]]
type Position = (Int, Int) -- y,x
opponent X = O
opponent O = X
instance Show (Maybe Player) where
show Nothing = "#"
show (Just O) = "O"
show (Just X) = "X"
showList [] = showString ""
showList (x:s) = showString (show x ++ " " ++ show s)
instance Show Board where
show [] = ""
show (row:x) = show row ++ "\n" ++ show x
instance Read (Maybe Player) where
readsPrec _ "X" = [(Just X, "")]
readsPrec _ "O" = [(Just O, "")]
readsPrec _ _ = [(Nothing, "")]
instance Read (Maybe Position) where
readsPrec _ input =
let
(yi,xs) = span isDigit input -- split on any character that's not a digit
(c:xi) = xs -- take off the first character of the x portion (it's the comma)
y = read yi :: Int
x = read xi :: Int
in
if all isDigit yi && length xs > 1 && c == ',' -- lazy eval & short circuiting ensure we don't hit a runtime error
then [(Just (y,x), "")]
else [(Nothing, "")]
-- pseudomutability rocks
replaceElement :: [a] -> Int -> a -> [a]
replaceElement xs i x = fore ++ (x:aft)
where (fore,aft) = (take i xs, drop (i+1) xs)
makeMove :: Player -> Position -> Board -> Board
makeMove player (y,x) board = replaceElement board y row
where row = replaceElement (board !! y) x (Just player)
checkGame :: Board -> GameResult
checkGame board = False
-- not implemented yet
choosePlayer :: IO Player
choosePlayer = do
putStrLn $ "TicTacToe! Choose (X/O):"
playerStr <- getLine
let player = read playerStr :: Maybe Player
if player == Nothing
then do
putStrLn $ "Invalid choice dumbass!"
choosePlayer
else let (Just p) = player in return p
divide :: Int -> Int -> Int
divide a b = if a < b then 0 else (divide (a-b) b)
chooseMove :: Player -> IO Position
chooseMove player = do
putStrLn $ "Your Move " ++ show (Just player) ++ " (y0-2,x0-2):"
moveStr <- getLine
let move = read moveStr :: Maybe Position
if move == Nothing
then do
putStrLn $ "Invalid move dumbass!"
chooseMove player
else let (Just m) = move in return m
gameLoop :: Board -> Player -> IO (Maybe Player)
gameLoop board player = do
if checkGame board
then return (winner board)
else do
move <- chooseMove player
let newBoard = makeMove player move board
putStrLn $ show newBoard
gameLoop newBoard (opponent player)
main :: IO ()
main = do
player <- choosePlayer
let board = [[Nothing, Nothing, Nothing],
[Nothing, Nothing, Nothing],
[Nothing, Nothing, Nothing]] :: Board
putStrLn $ show board
champion <- gameLoop board player
putStrLn $ "Game over, " ++ show champion ++ " won."