Skip to content

Instantly share code, notes, and snippets.

@christianscott
Created May 2, 2017 03:16
Show Gist options
  • Save christianscott/2764ed21ef1697165223f82b94702c28 to your computer and use it in GitHub Desktop.
Save christianscott/2764ed21ef1697165223f82b94702c28 to your computer and use it in GitHub Desktop.
Rock paper scissors in Haskell
module RPS where
import Data.Char (isSpace, toUpper)
import Data.Maybe (isNothing)
import Data.Text (strip)
data Move = Rock | Paper | Scissors
deriving (Show, Eq, Enum)
instance Ord Move where
(<=) x y = x == y || elem (x, y) pairs
where
pairs = [(Rock, Paper), (Paper, Scissors), (Scissors, Rock)]
data Outcome = Win | Loss | Draw
deriving Show
{-
Computer Strategy
Based on the fact that if the player loses, they will probably switch.
If they win, they will probably stay with their previous choice.
-}
-- Move for when the computer just won
winnerMove :: Move -> Move
winnerMove move = case move of
Rock -> Scissors
Paper -> Rock
Scissors -> Paper
-- Move for when computer just lost
loserMove :: Move -> Move
loserMove move = case move of
Rock -> Scissors
Paper -> Rock
Scissors -> Paper
getNextComputerMove :: Move -> Outcome -> Move
getNextComputerMove move outcome = case outcome of
Win -> winnerMove move
_ -> loserMove move
getOutcome :: Move -> Move -> Outcome
getOutcome user computer =
if user <= computer
then if user == computer
then Draw
else Loss
else Win
-- Prompt the user to input a move
getUserInput :: IO String
getUserInput = do
putStr "Next move: "
getLine
-- Parse input and maybe return a move
parseInput :: String -> Maybe Move
parseInput string = case filter (not . isSpace) (map toUpper string) of
"ROCK" -> Just Rock
"PAPER" -> Just Paper
"SCISSORS" -> Just Scissors
_ -> Nothing
-- Prompt the user until they enter a valid move
getUserMove :: IO (Move)
getUserMove = do
maybeMove <- parseInput <$> getUserInput
case maybeMove of
Nothing -> do
putStrLn "Please enter a valid move."
getUserMove
(Just move) -> return move
runGame :: Maybe Move -> Maybe Outcome -> IO ()
runGame Nothing Nothing = do
userMove <- getUserMove
let outcome = getOutcome userMove Rock
putStrLn $ "Outcome is a " ++ (show outcome)
runGame (Just Rock) (Just outcome)
runGame (Just move) (Just outcome) = do
userMove <- getUserMove
let nextMove = getNextComputerMove move outcome
let outcome = getOutcome userMove nextMove
putStrLn $ "Outcome is a " ++ (show outcome)
runGame (Just nextMove) (Just outcome)
main :: IO ()
main = runGame Nothing Nothing
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment