mattm177
mattm177

Reputation: 35

How to exit out of IO in Haskell by checking if a win condition is met?

I'm trying to implement the game connect four in Haskell. It's mostly functional at this point, but I'm having trouble passing the fact that the game has ended to the IO recursive function. Currently, the code will state that I have a "non exhaustive pattern in function gameloop" and I don't know how to exit out properly when a winstate is achieved.

Here's some code snippets:

data Action = Move Piece State Col   -- do Piece in State
            | Start              -- returns starting state
data Result = EndOfGame Int         -- end of game
            | ContinueGame State
         deriving (Eq, Show)

type Game = Action -> Result


connectfour :: Game
connectfour Start = ContinueGame ([],[],[],[],[],[],[])
connectfour (Move move state col)
    | win move (addPiece move state col) col = EndOfGame move -- player of Piece value move wins
    | isTie (addPiece move state col) = EndOfGame 0 -- no moves, tie
    | otherwise = ContinueGame (addPiece move state col)


gameLoop (ContinueGame state) player = do
  let turn = if player == 1 then 2 else 1
  -- Removed code for forum, just prepping values to feed into printboard and printing dialog
  putStrLn "Please select a column to enter your piece"
  input <- getLine
  gameLoop (connectfour (Move turn state (read input :: Int))) turn

TDLR; I'm trying to return a string saying which player has won on exit, but I don't know how to write a condition that checks for this in gameloop.

Upvotes: 2

Views: 716

Answers (1)

Alec
Alec

Reputation: 32309

You just need to add a case for EndOfGame in gameLoop:

gameLoop :: Result -> Int -> IO ()
gameLoop (EndOfGame move) _ = putStrLn ("Game over! Player " ++ show move ++ " won")
gameLoop (ContinueGame state) player = do
  {- omitted -}
  gameLoop (connectfour (Move turn state (read input :: Int))) turn

The "non exhaustive pattern in function gameloop" warning is telling you that gameLoop is missing a case - the EndOfGame one.


On another note, you might want to consider making a player ADT:

data Player = One | Two deriving (Show)

otherPlayer :: Player -> Player
otherPlayer One = Two
otherPlayer Two = One

Upvotes: 5

Related Questions