Created
October 16, 2017 05:02
-
-
Save kkweon/d13e7a5672a42c5ca58206babfc6a0f4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-| | |
# 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