```1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 ``` ```module Main where import Control.Applicative ((<\$>)) import Control.Monad (forever) import Control.Monad.Trans (lift) import Control.Monad.State (StateT, evalStateT, get, put) import System.Random (getStdRandom, randomR) data Move = Rock | Paper | Scissors deriving (Show, Eq, Enum) data Result = HumanWins | AIWins | Draw deriving (Show, Eq) beats :: Move -> Move -> Maybe Bool Rock `beats` Scissors = Just True Scissors `beats` Paper = Just True Paper `beats` Rock = Just True x `beats` y | x == y = Nothing | otherwise = Just False -- 1 - Rock, 2 - Paper, 3 - Scissors intToMove :: Int -> Move intToMove n = toEnum \$ n - 1 askHumanMove :: IO Move askHumanMove = do putStr "Enter your move (1 - Rock, 2 - Paper, 3 - Scissors): " intToMove <\$> (read :: String -> Int) <\$> getLine generateAIMove :: IO Move generateAIMove = intToMove <\$> (getStdRandom \$ randomR (1, 3)) doMove :: IO Result doMove = do aiMove <- generateAIMove humanMove <- askHumanMove putStrLn \$ "AI move - " ++ (show aiMove) ++ ", human move - " ++ (show humanMove) return \$ case aiMove `beats` humanMove of Just True -> AIWins Just False -> HumanWins _ -> Draw gameStep :: StateT (Int, Int) IO () gameStep = do s@(aiScore, humanScore) <- get result <- lift doMove newScore <- case result of Draw -> lift (putStrLn "Draw... Once again!") >> return s AIWins -> lift (putStrLn "AI wins!") >> return (aiScore + 1, humanScore) HumanWins -> lift (putStrLn "Human wins!") >> return (aiScore, humanScore + 1) lift \$ displayScore newScore put newScore displayScore :: (Int, Int) -> IO () displayScore (aiScore, humanScore) = putStrLn \$ "SCORE - " ++ (show aiScore) ++ ":" ++ (show humanScore) ++ " (AI:Human)" main :: IO () main = evalStateT (forever gameStep) (0, 0) ```