Skip to content

Instantly share code, notes, and snippets.

@kkweon
Created October 16, 2017 05:02
Show Gist options
  • Save kkweon/d13e7a5672a42c5ca58206babfc6a0f4 to your computer and use it in GitHub Desktop.
Save kkweon/d13e7a5672a42c5ca58206babfc6a0f4 to your computer and use it in GitHub Desktop.
{-|
# Description
- Random Number between 1 and 100 is generated
- User has to guess a number between 1 and 100
- The logic
CASE guess of
Correct ->
Prompt User to replay
False -> do
Reduce LIFE
IF game over
Prompt User to replay
ENDIF
CALL the logic again with reduce life
# How to Play
ghci> load NumberGuess
ghci> main
-}
module NumberGuess where
import Data.Char (toLower)
import System.Random (randomRIO)
-- | IF answer < user.input THEN `Lower` else `Higher` or `Correct` if equal
data Flag
= Correct
| Lower
| Higher
deriving (Show, Eq)
-- | Game State `guess` is kept because of a prompt (Answer is higher/lower than `guess`)
data GameState = GameState
{ answer :: Int
, life :: Int
, flag :: Flag
, guess :: Int
} deriving (Show)
-- | User can make a guess as long as `maxLife` > 0
maxLife :: Int
maxLife = 5
-- | Creates an initial game state
-- | `flag` and `guess` will be overwritten
mkGameState :: Int -> GameState
mkGameState ans =
GameState {answer = ans, life = maxLife, flag = Correct, guess = 0}
-- | Generates a random number
makeNumber :: IO Int
makeNumber = randomRIO ((1, 100) :: (Int, Int))
-- | Checks `guess` and reduces a life
processGuess :: Int -> GameState -> GameState
processGuess guess state@(GameState {life = life, answer = answer})
| answer == guess = state {flag = Correct, guess = guess}
| answer < guess = state {flag = Lower, life = life - 1, guess = guess}
| otherwise = state {flag = Higher, life = life - 1, guess = guess}
-- | Prints message accordingly
printMessage :: GameState -> IO ()
printMessage GameState {flag = Correct, guess = guess} =
putStrLn $ "Wow you got it. The answer is " ++ show guess
printMessage GameState {flag = Higher, guess = guess} =
putStrLn $ "Answer is higher than " ++ show guess
printMessage GameState {flag = Lower, guess = guess} =
putStrLn $ "Answer is lower than " ++ show guess
handleRestartPrompt :: String -> (GameState -> IO ()) -> IO ()
handleRestartPrompt input gamePlayFn = do
case map toLower input of
"yes" -> do
seed <- makeNumber
let gamestate = mkGameState seed
gamePlayFn gamestate
"y" -> do
seed <- makeNumber
let gamestate = mkGameState seed
gamePlayFn gamestate
_ -> return ()
-- | Check if flag is `Correct` or no life then asks user if he wants to play again
handleGameEnding :: (GameState -> IO ()) -> GameState -> IO ()
handleGameEnding gamePlayFn state@(GameState { flag = flag
, life = life
, answer = answer
})
| flag == Correct = do
putStrLn "You win. Do you want to play again? (Y/Yes or N/No)"
prompt <- getLine
handleRestartPrompt prompt gamePlayFn
| life <= 0 = do
putStrLn $
"You lost. Answer was " ++
show answer ++ " Do you want to play again? (Y/Yes or N/No)"
prompt <- getLine
handleRestartPrompt prompt gamePlayFn
| otherwise = do gamePlayFn state
-- | Make sure the input is `Int` type
safeInput :: IO Int
safeInput = do
putStrLn "Guess a number (1 <= answer <= 100): "
guess <- getLine
case reads guess :: [(Int, String)] of
[] -> safeInput
[(value, _)] -> return value
-- | Gets a guess from user and prints information
-- | `handleGameEnding` will handle the result
playGame :: GameState -> IO ()
playGame gameState = do
guess <- safeInput
let nextState = processGuess guess gameState
printMessage nextState
handleGameEnding playGame nextState
main :: IO ()
main = do
ans <- makeNumber
playGame (mkGameState ans)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment