Skip to content

Instantly share code, notes, and snippets.

@ddellacosta
Last active December 19, 2020 23:18
Show Gist options
  • Save ddellacosta/fea546b5c0af4f5cd3721e4292342ec0 to your computer and use it in GitHub Desktop.
Save ddellacosta/fea546b5c0af4f5cd3721e4292342ec0 to your computer and use it in GitHub Desktop.
Advent of Code Day 18 solution in Haskell
{-# LANGUAGE LambdaCase #-}
module Day18_2 where
import Data.Text as T
import Data.Void
import System.IO
import Text.Megaparsec
import Text.Megaparsec.Char
import qualified Text.Megaparsec.Char.Lexer as L
import Control.Monad.Reader
import Text.Pretty.Simple
data Part = One | Two
deriving (Show)
data Opts = Opts
{ part :: Part }
deriving (Show)
type Parser = ParsecT Void Text (Reader Opts)
parseOp1 :: Int -> Int -> (Int -> Parser Int) -> Char -> Parser Int
parseOp1 d1 d2 p = \case
'+' -> p (d1 + d2)
'*' -> p (d1 * d2)
parseOp2 :: Int -> Int -> (Int -> Parser Int) -> Char -> Parser Int
parseOp2 d1 d2 p = \case
'+' -> p (d1 + d2)
'*' -> (p d2) >>= pure . (d1 *)
termBody :: Int -> Parser Int
termBody d1 = do
op <- (char '+' <|> char '*')
space
d2 <- (L.decimal :: Parser Int) <|> subTerm
space
opts <- ask
let opParseFn = case (part opts) of
One -> parseOp1
Two -> parseOp2
opParseFn d1 d2 termBody op <|> opParseFn d1 d2 pure op
subTerm :: Parser Int
subTerm = between (char '(') (char ')') term
term :: Parser Int
term = do
d1 <- (L.decimal :: Parser Int) <|> subTerm
space
termBody d1
terms :: Parser Int
terms = sum <$> manyTill term eof
main :: Part -> FilePath -> IO ()
main part file = withFile file ReadMode
(\fh -> do
contents <- hGetContents fh
pPrint $ ((flip runReader (Opts part)) . (runParserT terms "") . T.pack) contents)
-- e.g.
λ> main One "/home/dd/code/launchpad/day18-input.txt"
Right 6640667297513
λ> main Two "/home/dd/code/launchpad/day18-input.txt"
Right 451589894841552
λ>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment