data Reagent = Reagent { _quantity :: Int, _chemical :: String } deriving (Ord, Eq, Show)
-data Rule = Rule {_lhs :: S.Set Reagent, _rhs :: Reagent} deriving (Eq, Show)
+data Reaction = Reaction {_lhs :: S.Set Reagent, _rhs :: Reagent} deriving (Eq, Show)
-type RuleBase = M.Map String Rule
+type Reactions = M.Map String Reaction
type Requirement = M.Map String Int
main :: IO ()
main = do
text <- TIO.readFile "data/advent14.txt"
- -- let rules = successfulParse text
- -- let ruleBase = mkRuleBase rules
- let ruleBase = successfulParse text
- -- print rules
- -- print ruleBase
- print $ part1 ruleBase
- print $ part2 ruleBase
+ let reactions = successfulParse text
+ print $ part1 reactions
+ print $ part2 reactions
oreLimit :: Int
oreLimit = 10^12
-mkRuleBase :: [Rule] -> RuleBase
-mkRuleBase = foldl' addRule M.empty
- where addRule base rule = M.insert (_chemical $ _rhs rule) rule base
-
-
--- part1 rules = required!"ORE"
+-- part1 reactions = required!"ORE"
-- where required0 = M.singleton "FUEL" 1
--- required = produce rules required
-part1 rules = oreForFuel rules 1
+-- required = produce reactions required
+part1 reactions = oreForFuel reactions 1
-part2 rules = searchFuel rules (upper `div` 2) upper
- where upper = findUpper rules (oreLimit `div` base)
- base = oreForFuel rules 1
+part2 reactions = searchFuel reactions (upper `div` 2) upper
+ where upper = findUpper reactions (oreLimit `div` base)
+ base = oreForFuel reactions 1
-oreForFuel :: RuleBase -> Int -> Int
-oreForFuel rules n = required!"ORE"
+oreForFuel :: Reactions -> Int -> Int
+oreForFuel reactions n = required!"ORE"
where required0 = M.singleton "FUEL" n
- required = produce rules required0
+ required = produce reactions required0
-findUpper :: RuleBase -> Int -> Int
+findUpper :: Reactions -> Int -> Int
-- findUpper _ n | trace ("Upper " ++ show n) False = undefined
-findUpper rules n = if ore > oreLimit
+findUpper reactions n = if ore > oreLimit
then n
- else findUpper rules (n * 2)
- where ore = oreForFuel rules n
+ else findUpper reactions (n * 2)
+ where ore = oreForFuel reactions n
-searchFuel :: RuleBase -> Int -> Int -> Int
+searchFuel :: Reactions -> Int -> Int -> Int
-- searchFuel _ lower upper | trace ("Search " ++ show lower ++ " - " ++ show upper) False = undefined
-searchFuel rules lower upper
+searchFuel reactions lower upper
| upper == lower = upper
| otherwise = if ore > oreLimit
- then searchFuel rules lower (mid - 1)
- else searchFuel rules mid upper
+ then searchFuel reactions lower (mid - 1)
+ else searchFuel reactions mid upper
where mid = (upper + lower + 1) `div` 2
- ore = oreForFuel rules mid
+ ore = oreForFuel reactions mid
-produce :: RuleBase -> Requirement -> Requirement
-produce rules required
+produce :: Reactions -> Requirement -> Requirement
+produce reactions required
| M.null outstanding = required
- | otherwise = produce rules required''
+ | otherwise = produce reactions required''
where outstanding = M.filter (> 0) $ nonOre required
(chem, qty) = M.findMin outstanding
- rule = rules!chem
- productQty = _quantity $ _rhs rule
+ reaction = reactions!chem
+ productQty = _quantity $ _rhs reaction
applications = max 1 (qty `div` productQty)
qty' = qty - (applications * productQty)
required' = M.insert chem qty' required
- required'' = S.foldl (addRequrirement applications) required' (_lhs rule)
+ required'' = S.foldl (addRequrirement applications) required' (_lhs reaction)
nonOre :: Requirement -> Requirement
commaP = symb ","
identifierP = some alphaNumChar <* sc
-rulesP = mkRuleBase <$> many ruleP
+reactionsP = mkReactions <$> many reactionP
-ruleP = Rule <$> reagentsP <* arrowP <*> reagentP
+reactionP = Reaction <$> reagentsP <* arrowP <*> reagentP
reagentP = Reagent <$> integer <*> identifierP
reagentsP = S.fromList <$> reagentP `sepBy` commaP
+mkReactions :: [Reaction] -> Reactions
+mkReactions = foldl' addReaction M.empty
+ where addReaction base reaction = M.insert (_chemical $ _rhs reaction) reaction base
+
-- successfulParse :: Text -> [Vec]
-successfulParse :: Text -> RuleBase
+successfulParse :: Text -> Reactions
successfulParse input =
- case parse rulesP "input" input of
+ case parse reactionsP "input" input of
Left _err -> M.empty -- TIO.putStr $ T.pack $ parseErrorPretty err
- Right rules -> rules
+ Right reactions -> reactions