module Main where import System.Random (randomRIO) import Data.IORef import Data.Char (toUpper) main :: IO () main = do putStrLn "*** BAGELS : HASKELL ***" running <- newIORef True gameOver <- newIORef False score <- newIORef 0 number <- newIORef 0 guess <- newIORef 0 attempt <- newIORef 0 guessed <- newIORef False resp <- askToSeeTheRules if resp then do displayRules else putStrLn "" runningLoop running gameOver score number guess attempt guessed displayRules :: IO () displayRules = do putStrLn "I WILL THINK OF A THREE-DIGIT NUMBER. YOU WILL TRY TO" putStrLn "GUESS MY NUMBER AND I WILL GIVE YOU CLUES AS FOLLOWS:" putStrLn " PICO - ONE DIGIT CORRECT BUT IN THE WRONG POSITION" putStrLn " FERMI - ONE DIGIT CORRECT AND IN THE RIGHT POSITION" putStrLn " BAGELS - NO DIGITS ARE CORRECT" putStrLn "" putStrLn "YOU GET TWENTY TRIES BEFORE YOU LOSE." putStrLn "" displayGameOver :: IORef Int -> IO () displayGameOver number = do numberVal <- readIORef number putStrLn "OH WELL, THAT WAS TWENTY GUESSES." putStrLn $ "MY NUMBER WAS " ++ show numberVal ++ "." createDigit2 :: Int -> IO Int createDigit2 digit1 = do digit2 <- randomRIO (0, 9) if digit2 == digit1 then createDigit2 digit1 else return digit2 createDigit3 :: Int -> Int -> IO Int createDigit3 digit1 digit2 = do digit3 <- randomRIO (0, 9) if digit3 == digit1 || digit3 == digit2 then createDigit3 digit1 digit2 else return digit3 createTheNumber :: IO Int createTheNumber = do digit1 <- randomRIO (1, 9) digit2 <- createDigit2 digit1 digit3 <- createDigit3 digit1 digit2 let numberVal = (digit1 * 100) + (digit2 * 10) + digit3 return numberVal checkGuess :: IORef Int -> IORef Int -> IO Bool checkGuess guess number = do numberVal <- readIORef number guessVal <- readIORef guess let tmp1 = guessVal `div` 100 let tmp2 = (guessVal `mod` 100) `div` 10 let tmp3 = guessVal `mod` 10 let digit1 = numberVal `div` 100 let digit2 = (numberVal `mod` 100) `div` 10 let digit3 = numberVal `mod` 10 let val1 = if tmp1 == digit1 then 1 else if tmp1 == digit2 || tmp1 == digit3 then 2 else 0 let val2 = if tmp2 == digit2 then 1 else if tmp2 == digit1 || tmp2 == digit3 then 2 else 0 let val3 = if tmp3 == digit3 then 1 else if tmp3 == digit1 || tmp3 == digit2 then 2 else 0 if val1 == 1 && val2 == 1 && val3 == 1 then return True else do if val1 == 0 && val2 == 0 && val3 == 0 then putStrLn "BAGELS" else do putStrLn $ concat [if val1 == 1 then "FERMI " else if val1 == 2 then "PICO " else "", if val2 == 1 then "FERMI " else if val2 == 2 then "PICO " else "", if val3 == 1 then "FERMI" else if val3 == 2 then "PICO" else ""] return False askForGuess :: IORef Int -> IO Int askForGuess attempt = do attemptVal <- readIORef attempt putStrLn $ "GUESS #" ++ show attemptVal guess <- readLn if guess < 0 then do putStrLn "PLEASE GUESS A NON-NEGATIVE NUMBER." askForGuess attempt else if guess < 100 || guess > 999 then do putStrLn "PLEASE GUESS A NUMBER BETWEEN 100 AND 999." askForGuess attempt else do return guess runningLoop :: IORef Bool -> IORef Bool -> IORef Int -> IORef Int -> IORef Int -> IORef Int -> IORef Bool -> IO () runningLoop running gameOver score number guess attempt guessed = do runningVal <- readIORef running if runningVal then do writeIORef attempt 1 writeIORef gameOver False numberVal <- createTheNumber writeIORef number numberVal putStrLn "OK, I HAVE A NUMBER IN MIND." gameLoop running gameOver score number guess attempt guessed else do scoreVal <- readIORef score putStrLn $ "A " ++ show scoreVal ++ " POINT BAGLES BUFF!" putStrLn "HOPE YOU HAD FUN. BYE!" gameLoop :: IORef Bool -> IORef Bool -> IORef Int -> IORef Int -> IORef Int -> IORef Int -> IORef Bool -> IO () gameLoop running gameOver score number guess attempt guessed = do gameOverVal <- readIORef gameOver if not gameOverVal then do guessVal <- askForGuess attempt writeIORef guess guessVal guessedVal <- checkGuess guess number if guessedVal then do putStrLn "YOU GOT IT!!!" modifyIORef score (\s -> s + 1) writeIORef gameOver True gameLoop running gameOver score number guess attempt guessed else do modifyIORef attempt (\a -> a + 1) attemptVal <- readIORef attempt if attemptVal > 20 then do displayGameOver number writeIORef gameOver True else do gameLoop running gameOver score number guess attempt guessed else do putStrLn "*** GAME OVER ***" runningVal <- askToPlayAgain writeIORef running runningVal runningLoop running gameOver score number guess attempt guessed askQuestion :: String -> IO Bool askQuestion prompt = do putStrLn (prompt ++ "?") ans <- getLine let answer = map toUpper ans if answer == "YES" || answer == "Y" then return True else if answer == "NO" || answer == "N" then return False else if answer == "" then do putStrLn "PLEASE ANSWER THE QUESTION." askQuestion prompt else do putStrLn "PLEASE ANSWER \"YES\" OR \"NO\"" askQuestion prompt askToSeeTheRules :: IO Bool askToSeeTheRules = askQuestion "DO YOU WANT TO SEE THE RULES" askToPlayAgain :: IO Bool askToPlayAgain = askQuestion "DO YOU WANT TO PLAY AGAIN"