57 lines
1.9 KiB
Haskell
57 lines
1.9 KiB
Haskell
|
module Day18 where
|
||
|
|
||
|
import AoC
|
||
|
|
||
|
import Control.Applicative
|
||
|
import Data.Maybe
|
||
|
import Text.ParserCombinators.ReadP
|
||
|
import Text.Read.Lex
|
||
|
|
||
|
data Expression = Literal Int
|
||
|
| Addition Expression Expression
|
||
|
| Multiplication Expression Expression
|
||
|
| Bracketed Expression
|
||
|
|
||
|
type ApplicationSequencer = Expression -> String -> Expression -> Expression
|
||
|
|
||
|
parseLiteral :: ReadP Expression
|
||
|
parseLiteral = Literal <$> readDecP
|
||
|
|
||
|
parseBracketed :: ApplicationSequencer -> ReadP Expression
|
||
|
parseBracketed seq = Bracketed <$> between (char '(') (char ')') (parseExpression seq)
|
||
|
|
||
|
parseOperations :: ApplicationSequencer -> ReadP Expression
|
||
|
parseOperations seq =
|
||
|
do l <- parseLiteral <|> parseBracketed seq
|
||
|
apps <- many1 $ parseApplication seq
|
||
|
return $ foldl (\l (op, r) -> seq l op r) l apps
|
||
|
|
||
|
parseApplication :: ApplicationSequencer -> ReadP (String, Expression)
|
||
|
parseApplication seq =
|
||
|
do skipSpaces
|
||
|
op <- choice $ map string ["*", "+"]
|
||
|
skipSpaces
|
||
|
r <- parseLiteral <|> parseBracketed seq
|
||
|
return $ (op, r)
|
||
|
|
||
|
parseExpression :: ApplicationSequencer -> ReadP Expression
|
||
|
parseExpression seq = parseLiteral <|> parseOperations seq <|> parseBracketed seq
|
||
|
|
||
|
sequenceLeftToRight :: ApplicationSequencer
|
||
|
sequenceLeftToRight l op r = toOperation op l r
|
||
|
where toOperation "*" = Multiplication
|
||
|
toOperation "+" = Addition
|
||
|
|
||
|
sequenceAdditionPrecedence :: ApplicationSequencer
|
||
|
sequenceAdditionPrecedence (Multiplication l r) "+" rr = Multiplication l (Addition r rr)
|
||
|
sequenceAdditionPrecedence l op r = sequenceLeftToRight l op r
|
||
|
|
||
|
eval :: Expression -> Int
|
||
|
eval (Literal n) = n
|
||
|
eval (Addition l r) = eval l + eval r
|
||
|
eval (Multiplication l r) = eval l * eval r
|
||
|
eval (Bracketed x) = eval x
|
||
|
|
||
|
main = runAoC lines (run sequenceLeftToRight) (run sequenceAdditionPrecedence)
|
||
|
where run seq = sum . map (eval . fromJust . oneCompleteResult (parseExpression seq))
|