RosettaCodeData/Task/24-game/Haskell/24-game.hs

54 lines
1.6 KiB
Haskell
Raw Permalink Normal View History

2017-09-23 10:01:46 +02:00
import Data.List (sort)
import Data.Char (isDigit)
import Data.Maybe (fromJust)
import Control.Monad (foldM)
import System.Random (randomRs, getStdGen)
import System.IO (hSetBuffering, stdout, BufferMode(NoBuffering))
2013-04-10 14:23:37 -07:00
main = do
2017-09-23 10:01:46 +02:00
hSetBuffering stdout NoBuffering
mapM_
putStrLn
[ "THE 24 GAME\n"
, "Given four digits in the range 1 to 9"
, "Use the +, -, *, and / operators in reverse polish notation"
, "To show how to make an answer of 24.\n"
]
digits <- fmap (sort . take 4 . randomRs (1, 9)) getStdGen :: IO [Int]
putStrLn ("Your digits: " ++ unwords (fmap show digits))
guessLoop digits
where
guessLoop digits =
putStr "Your expression: " >> fmap (processGuess digits . words) getLine >>=
either (\m -> putStrLn m >> guessLoop digits) putStrLn
2013-04-10 14:23:37 -07:00
2017-09-23 10:01:46 +02:00
processGuess _ [] = Right ""
processGuess digits xs
| not matches = Left "Wrong digits used"
where
matches = digits == (sort . fmap read $ filter (all isDigit) xs)
2013-04-10 14:23:37 -07:00
processGuess digits xs = calc xs >>= check
2017-09-23 10:01:46 +02:00
where
check 24 = Right "Correct"
check x = Left (show (fromRational (x :: Rational)) ++ " is wrong")
2013-04-10 14:23:37 -07:00
-- A Reverse Polish Notation calculator with full error handling
2017-09-23 10:01:46 +02:00
calc xs =
foldM simplify [] xs >>=
\ns ->
(case ns of
[n] -> Right n
_ -> Left "Too few operators")
2013-04-10 14:23:37 -07:00
2017-09-23 10:01:46 +02:00
simplify (a:b:ns) s
| isOp s = Right ((fromJust $ lookup s ops) b a : ns)
simplify _ s
| isOp s = Left ("Too few values before " ++ s)
simplify ns s
| all isDigit s = Right (fromIntegral (read s) : ns)
simplify _ s = Left ("Unrecognized symbol: " ++ s)
2013-04-10 14:23:37 -07:00
2017-09-23 10:01:46 +02:00
isOp v = elem v $ fmap fst ops
2013-04-10 14:23:37 -07:00
2017-09-23 10:01:46 +02:00
ops = [("+", (+)), ("-", (-)), ("*", (*)), ("/", (/))]