How to resolve the algorithm 24 game step by step in the Haskell programming language
How to resolve the algorithm 24 game step by step in the Haskell programming language
Table of Contents
Problem Statement
The 24 Game tests one's mental arithmetic.
Write a program that randomly chooses and displays four digits, each from 1 ──► 9 (inclusive) with repetitions allowed. The program should prompt for the player to enter an arithmetic expression using just those, and all of those four digits, used exactly once each. The program should check then evaluate the expression. The goal is for the player to enter an expression that (numerically) evaluates to 24.
Let's start with the solution:
Step by Step solution about How to resolve the algorithm 24 game step by step in the Haskell programming language
This Haskell program implements a game where the user is given four digits and has to find an expression using those digits and the +, -, *, and / operators in reverse polish notation that results in 24. The program uses a fold to evaluate the expression and handle errors.
The main function sets the output buffering to unbuffered, so that the output is printed immediately. It then prints the game instructions and the four digits that the user will be using.
The guessLoop function prompts the user for an expression and tries to evaluate it. If the expression is valid and evaluates to 24, it prints "Correct". Otherwise, it prints an error message. The expression is passed to the processGuess function, which checks that the digits used in the expression are the same as the four digits that were given to the user. If the digits are not the same, it returns an error message. Otherwise, it passes the expression to the calc function, which evaluates the expression and returns the result.
The calc function uses a fold to evaluate the expression. The fold takes two arguments: a list of numbers and an operator. The fold iterates over the list of numbers, applying the operator to each number in turn. The result of the fold is a list of numbers.
The fold is implemented using the foldM function from the Control.Monad module. The foldM function takes three arguments: a monad, a starting value, and a list of values. The foldM function iterates over the list of values, applying the monad to each value in turn. The result of the foldM function is a value of the monad type.
In this case, the monad is the Maybe monad. The Maybe monad is a monad that represents optional values. The Maybe monad has two constructors: Nothing and Just. The Nothing constructor represents the absence of a value. The Just constructor represents the presence of a value.
The foldM function is used to evaluate the expression. The starting value of the foldM function is an empty list. The list of values is the list of numbers in the expression. The monad that is used is the Maybe monad. The monad operation that is used is the >>= operator. The >>= operator is a monad operator that binds a value to a monad.
The >>= operator is used to bind the result of the foldM function to the check function. The check function checks if the result of the foldM function is 24. If the result is 24, the check function returns the Right constructor of the Maybe monad. The Right constructor represents the presence of a value. The value that is represented by the Right constructor is the string "Correct".
If the result of the foldM function is not 24, the check function returns the Left constructor of the Maybe monad. The Left constructor represents the absence of a value. The value that is represented by the Left constructor is an error message.
The result of the foldM function is a Maybe value. The Maybe value is either the Right constructor with the value of "Correct" or the Left constructor with an error message. The either function is used to extract the value from the Maybe value. The either function takes two arguments: a function to handle the Left constructor and a function to handle the Right constructor.
The either function is used to handle the result of the foldM function. If the result of the foldM function is the Right constructor, the either function calls the function that is passed as the second argument. The function that is passed as the second argument prints the string "Correct".
If the result of the foldM function is the Left constructor, the either function calls the function that is passed as the first argument. The function that is passed as the first argument prints the error message that is represented by the Left constructor.
Source code in the haskell programming language
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))
main = do
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
processGuess _ [] = Right ""
processGuess digits xs
| not matches = Left "Wrong digits used"
where
matches = digits == (sort . fmap read $ filter (all isDigit) xs)
processGuess digits xs = calc xs >>= check
where
check 24 = Right "Correct"
check x = Left (show (fromRational (x :: Rational)) ++ " is wrong")
-- A Reverse Polish Notation calculator with full error handling
calc xs =
foldM simplify [] xs >>=
\ns ->
(case ns of
[n] -> Right n
_ -> Left "Too few operators")
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)
isOp v = elem v $ fmap fst ops
ops = [("+", (+)), ("-", (-)), ("*", (*)), ("/", (/))]
You may also check:How to resolve the algorithm Euler method step by step in the ZX Spectrum Basic programming language
You may also check:How to resolve the algorithm Find common directory path step by step in the Arturo programming language
You may also check:How to resolve the algorithm Vector products step by step in the uBasic/4tH programming language
You may also check:How to resolve the algorithm Universal Turing machine step by step in the EchoLisp programming language
You may also check:How to resolve the algorithm Matrix transposition step by step in the Erlang programming language