This repository has been archived by the owner on Nov 17, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 8
/
Day18.hs
77 lines (66 loc) · 2.15 KB
/
Day18.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
{-# LANGUAGE OverloadedStrings #-}
-- |
-- Module : AOC.Challenge.Day18
-- License : BSD3
--
-- Stability : experimental
-- Portability : non-portable
--
-- Day 18. See "AOC.Solver" for the types used in this module!
module AOC.Challenge.Day18 (
day18a
, day18b
) where
import AOC.Solver ((:~>)(..))
import Control.Monad (MonadPlus)
import Data.Char (digitToInt)
import Data.Void (Void)
import qualified Text.Megaparsec as P
import qualified Text.Megaparsec.Char as P
type Parser = P.Parsec Void String
-- | A right-associative syntax
data Syntax f a = Syntax
{ sBinOps :: [f (a -> a -> a)] -- ^ Operations at each level; highest precedence is last.
, sPrim :: f a -- ^ How to parse a primitive
, sPar :: f a -> f a -- ^ parentheses
}
exprSyntax1 :: Syntax Parser Int
exprSyntax1 = Syntax
{ sBinOps = [ P.choice [ (*) <$ " * ", (+) <$ " + " ] ] -- all same level
, sPrim = digitToInt <$> P.digitChar
, sPar = P.between "(" ")"
}
exprSyntax2 :: Syntax Parser Int
exprSyntax2 = Syntax
{ sBinOps = [ (*) <$ " * " -- + higher than *
, (+) <$ " + "
]
, sPrim = digitToInt <$> P.digitChar
, sPar = P.between "(" ")"
}
parseSyntax :: forall f a. MonadPlus f => Syntax f a -> f a
parseSyntax Syntax{..} = parseTopLevel
where
parseTopLevel :: f a
parseTopLevel = parseLevels sBinOps
parseLevels :: [f (a -> a -> a)] -> f a
parseLevels = \case
[] -> sPrim P.<|> sPar parseTopLevel
o:os ->
let parseDown = parseLevels os
parseThisLevelWith x = (P.<|> pure x) $ do
f <- o
y <- parseDown
parseThisLevelWith (f x y)
in parseDown >>= parseThisLevelWith
day18 :: (Num a, Show a) => Syntax Parser a -> String :~> a
day18 s = MkSol
{ sParse = Just
, sShow = show
, sSolve = P.parseMaybe $ sum <$> (parseSyntax s `P.sepBy` P.newline)
}
{-# INLINE day18 #-}
day18a :: String :~> Int
day18a = day18 exprSyntax1
day18b :: String :~> Int
day18b = day18 exprSyntax2