-- tic-tac-toe.hs import List -- place a character in a particular place and return the new board place char index board = (take index board) ++ [char] ++ (drop (index + 1) board) -- returns winner: X, O, -, C winner [a, b, c, _, _, _, _, _, _] | (a == b) && (b == c) && (a /= '-') = a winner [_, _, _, a, b, c, _, _, _] | (a == b) && (b == c) && (a /= '-') = a winner [_, _, _, _, _, _, a, b, c] | (a == b) && (b == c) && (a /= '-') = a winner [a, _, _, b, _, _, c, _, _] | (a == b) && (b == c) && (a /= '-') = a winner [_, a, _, _, b, _, _, c, _] | (a == b) && (b == c) && (a /= '-') = a winner [_, _, a, _, _, b, _, _, c] | (a == b) && (b == c) && (a /= '-') = a winner [a, _, _, _, b, _, _, _, c] | (a == b) && (b == c) && (a /= '-') = a winner [_, _, a, _, b, _, c, _, _] | (a == b) && (b == c) && (a /= '-') = a winner board = if elem '-' board then '-' else 'C' -- transform a numpad key to coordinates numberToCoords key = case key of "7" -> 0; "8" -> 1; "9" -> 2 "4" -> 3; "5" -> 4; "6" -> 5 "1" -> 6; "2" -> 7; "3" -> 8 _ -> error "Invalid Input" -- possible scores assigned to games data Score = Great | Ok | Awful | Impossible deriving Eq -- score the move and return it scoreMove board player index = if (board !! index) /= '-' then Impossible else -- place the move let new_board = place player index board in -- we need to know the other player let other = if player == 'O' then 'X' else 'O' in -- check if we won or tied if (winner new_board) == player then Great else if (winner new_board) == 'C' then Ok else -- find best score other player can get now let other_score = scoreMove new_board other (bestMove other new_board) in if other_score == Great then Awful else if other_score == Awful then Great else Ok -- return best move player can get bestMove player board = -- score all 9 moves (uses currying on scoreMove) let scores = map (scoreMove board player) [0 .. 8] in -- find index of the best move case findIndex ((==) Great) scores of Just i -> i Nothing -> case findIndex ((==) Ok) scores of Just i -> i Nothing -> case findIndex ((==) Awful) scores of Just i -> i Nothing -> 0 -- get the AI move getAi board = bestMove 'O' board -- print the board line by line printBoard "" = do putStrLn "\n" printBoard (a : b : c : rest) = do putStrLn (a : b : [c]) printBoard rest -- report the end of the game endgame w = do if w == 'C' then putStrLn "Cats Game!" else putStrLn (w : " has won!") -- main game loop game board = do if (winner board) /= '-' then endgame (winner board) else do -- print the board printBoard board -- get their input user <- getLine -- convert it to a coord, place the X and get the new board let board2 = place 'X' (numberToCoords user) board -- check for win again if (winner board) /= '-' then endgame (winner board) else do -- place the AI move and get the new board let board3 = place 'O' (getAi board2) board2 -- recurse on the new board game board3 -- main function main = do -- print a message and start with the empty board putStrLn "You are X, use number pad to play!" game "---------"