From 0cb8ce8d9c118041a6095764fe2672b2f67879ba Mon Sep 17 00:00:00 2001 From: Neil Smith <neil.git@njae.me.uk> Date: Mon, 16 Dec 2019 17:26:20 +0000 Subject: [PATCH] Renamed rule to reaction --- advent14/src/advent14.hs | 81 +++++++-------- problems/day14.html | 209 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 247 insertions(+), 43 deletions(-) create mode 100644 problems/day14.html diff --git a/advent14/src/advent14.hs b/advent14/src/advent14.hs index 1fafe9b..4e35ee2 100644 --- a/advent14/src/advent14.hs +++ b/advent14/src/advent14.hs @@ -17,75 +17,66 @@ import qualified Data.Set as S 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 @@ -114,16 +105,20 @@ arrowP = symb "=>" 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 diff --git a/problems/day14.html b/problems/day14.html new file mode 100644 index 0000000..3c6f506 --- /dev/null +++ b/problems/day14.html @@ -0,0 +1,209 @@ +<!DOCTYPE html> +<html lang="en-us"> +<head> +<meta charset="utf-8"/> +<title>Day 14 - Advent of Code 2019</title> +<!--[if lt IE 9]><script src="/static/html5.js"></script><![endif]--> +<link href='//fonts.googleapis.com/css?family=Source+Code+Pro:300&subset=latin,latin-ext' rel='stylesheet' type='text/css'> +<link rel="stylesheet" type="text/css" href="/static/style.css?24"/> +<link rel="stylesheet alternate" type="text/css" href="/static/highcontrast.css?0" title="High Contrast"/> +<link rel="shortcut icon" href="/favicon.png"/> +</head><!-- + + + + +Oh, hello! Funny seeing you here. + +I appreciate your enthusiasm, but you aren't going to find much down here. +There certainly aren't clues to any of the puzzles. The best surprises don't +even appear in the source until you unlock them for real. + +Please be careful with automated requests; I'm not a massive company, and I can +only take so much traffic. Please be considerate so that everyone gets to play. + +If you're curious about how Advent of Code works, it's running on some custom +Perl code. Other than a few integrations (auth, analytics, ads, social media), +I built the whole thing myself, including the design, animations, prose, and +all of the puzzles. + +The puzzles are most of the work; preparing a new calendar and a new set of +puzzles each year takes all of my free time for 4-5 months. A lot of effort +went into building this thing - I hope you're enjoying playing it as much as I +enjoyed making it for you! + +If you'd like to hang out, I'm @ericwastl on Twitter. + +- Eric Wastl + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +--> +<body> +<header><div><h1 class="title-global"><a href="/">Advent of Code</a></h1><nav><ul><li><a href="/2019/about">[About]</a></li><li><a href="/2019/events">[Events]</a></li><li><a href="https://teespring.com/adventofcode-2019" target="_blank">[Shop]</a></li><li><a href="/2019/settings">[Settings]</a></li><li><a href="/2019/auth/logout">[Log Out]</a></li></ul></nav><div class="user">Neil Smith <a href="/2019/support" class="supporter-badge" title="Advent of Code Supporter">(AoC++)</a> <span class="star-count">28*</span></div></div><div><h1 class="title-event"> <span class="title-event-wrap">/^</span><a href="/2019">2019</a><span class="title-event-wrap">$/</span></h1><nav><ul><li><a href="/2019">[Calendar]</a></li><li><a href="/2019/support">[AoC++]</a></li><li><a href="/2019/sponsors">[Sponsors]</a></li><li><a href="/2019/leaderboard">[Leaderboard]</a></li><li><a href="/2019/stats">[Stats]</a></li></ul></nav></div></header> + +<div id="sidebar"> +<div id="sponsor"><div class="quiet">Our <a href="/2019/sponsors">sponsors</a> help make Advent of Code possible:</div><div class="sponsor"><a href="https://www.codethink.co.uk/" target="_blank" onclick="if(ga)ga('send','event','sponsor','sidebar',this.href);" rel="noopener">Codethink Ltd.</a> - Codethink is a software services company, expert in the use of Open Source technologies for systems software engineering.</div></div> +</div><!--/sidebar--> + +<main> +<script>window.addEventListener('click', function(e,s,r){if(e.target.nodeName==='CODE'&&e.detail===3){s=window.getSelection();s.removeAllRanges();r=document.createRange();r.selectNodeContents(e.target);s.addRange(r);}});</script> +<article class="day-desc"><h2>--- Day 14: Space Stoichiometry ---</h2><p>As you approach the rings of Saturn, your ship's <em>low fuel</em> indicator turns on. There isn't any fuel here, but the rings have plenty of raw material. Perhaps your ship's <span title="Yes, the acronym is intentional.">Inter-Stellar Refinery Union</span> brand <em>nanofactory</em> can turn these raw materials into fuel.</p> +<p>You ask the nanofactory to produce a list of the <em>reactions</em> it can perform that are relevant to this process (your puzzle input). Every reaction turns some quantities of specific <em>input chemicals</em> into some quantity of an <em>output chemical</em>. Almost every <em>chemical</em> is produced by exactly one reaction; the only exception, <code>ORE</code>, is the raw material input to the entire process and is not produced by a reaction.</p> +<p>You just need to know how much <code><em>ORE</em></code> you'll need to collect before you can produce one unit of <code><em>FUEL</em></code>.</p> +<p>Each reaction gives specific quantities for its inputs and output; reactions cannot be partially run, so only whole integer multiples of these quantities can be used. (It's okay to have leftover chemicals when you're done, though.) For example, the reaction <code>1 A, 2 B, 3 C => 2 D</code> means that exactly 2 units of chemical <code>D</code> can be produced by consuming exactly 1 <code>A</code>, 2 <code>B</code> and 3 <code>C</code>. You can run the full reaction as many times as necessary; for example, you could produce 10 <code>D</code> by consuming 5 <code>A</code>, 10 <code>B</code>, and 15 <code>C</code>.</p> +<p>Suppose your nanofactory produces the following list of reactions:</p> +<pre><code>10 ORE => 10 A +1 ORE => 1 B +7 A, 1 B => 1 C +7 A, 1 C => 1 D +7 A, 1 D => 1 E +7 A, 1 E => 1 FUEL +</code></pre> +<p>The first two reactions use only <code>ORE</code> as inputs; they indicate that you can produce as much of chemical <code>A</code> as you want (in increments of 10 units, each 10 costing 10 <code>ORE</code>) and as much of chemical <code>B</code> as you want (each costing 1 <code>ORE</code>). To produce 1 <code>FUEL</code>, a total of <em>31</em> <code>ORE</code> is required: 1 <code>ORE</code> to produce 1 <code>B</code>, then 30 more <code>ORE</code> to produce the 7 + 7 + 7 + 7 = 28 <code>A</code> (with 2 extra <code>A</code> wasted) required in the reactions to convert the <code>B</code> into <code>C</code>, <code>C</code> into <code>D</code>, <code>D</code> into <code>E</code>, and finally <code>E</code> into <code>FUEL</code>. (30 <code>A</code> is produced because its reaction requires that it is created in increments of 10.)</p> +<p>Or, suppose you have the following list of reactions:</p> +<pre><code>9 ORE => 2 A +8 ORE => 3 B +7 ORE => 5 C +3 A, 4 B => 1 AB +5 B, 7 C => 1 BC +4 C, 1 A => 1 CA +2 AB, 3 BC, 4 CA => 1 FUEL +</code></pre> +<p>The above list of reactions requires <em>165</em> <code>ORE</code> to produce 1 <code>FUEL</code>:</p> +<ul> +<li>Consume 45 <code>ORE</code> to produce 10 <code>A</code>.</li> +<li>Consume 64 <code>ORE</code> to produce 24 <code>B</code>.</li> +<li>Consume 56 <code>ORE</code> to produce 40 <code>C</code>.</li> +<li>Consume 6 <code>A</code>, 8 <code>B</code> to produce 2 <code>AB</code>.</li> +<li>Consume 15 <code>B</code>, 21 <code>C</code> to produce 3 <code>BC</code>.</li> +<li>Consume 16 <code>C</code>, 4 <code>A</code> to produce 4 <code>CA</code>.</li> +<li>Consume 2 <code>AB</code>, 3 <code>BC</code>, 4 <code>CA</code> to produce 1 <code>FUEL</code>.</li> +</ul> +<p>Here are some larger examples:</p> +<ul> +<li><p><em>13312</em> <code>ORE</code> for 1 <code>FUEL</code>:</p> +<pre><code>157 ORE => 5 NZVS +165 ORE => 6 DCFZ +44 XJWVT, 5 KHKGT, 1 QDVJ, 29 NZVS, 9 GPVTF, 48 HKGWZ => 1 FUEL +12 HKGWZ, 1 GPVTF, 8 PSHF => 9 QDVJ +179 ORE => 7 PSHF +177 ORE => 5 HKGWZ +7 DCFZ, 7 PSHF => 2 XJWVT +165 ORE => 2 GPVTF +3 DCFZ, 7 NZVS, 5 HKGWZ, 10 PSHF => 8 KHKGT +</code></pre></li> +<li><p><em>180697</em> <code>ORE</code> for 1 <code>FUEL</code>:</p> +<pre><code>2 VPVL, 7 FWMGM, 2 CXFTF, 11 MNCFX => 1 STKFG +17 NVRVD, 3 JNWZP => 8 VPVL +53 STKFG, 6 MNCFX, 46 VJHF, 81 HVMC, 68 CXFTF, 25 GNMV => 1 FUEL +22 VJHF, 37 MNCFX => 5 FWMGM +139 ORE => 4 NVRVD +144 ORE => 7 JNWZP +5 MNCFX, 7 RFSQX, 2 FWMGM, 2 VPVL, 19 CXFTF => 3 HVMC +5 VJHF, 7 MNCFX, 9 VPVL, 37 CXFTF => 6 GNMV +145 ORE => 6 MNCFX +1 NVRVD => 8 CXFTF +1 VJHF, 6 MNCFX => 4 RFSQX +176 ORE => 6 VJHF +</code></pre></li> +<li><p><em>2210736</em> <code>ORE</code> for 1 <code>FUEL</code>:</p> +<pre><code>171 ORE => 8 CNZTR +7 ZLQW, 3 BMBT, 9 XCVML, 26 XMNCP, 1 WPTQ, 2 MZWV, 1 RJRHP => 4 PLWSL +114 ORE => 4 BHXH +14 VRPVC => 6 BMBT +6 BHXH, 18 KTJDG, 12 WPTQ, 7 PLWSL, 31 FHTLT, 37 ZDVW => 1 FUEL +6 WPTQ, 2 BMBT, 8 ZLQW, 18 KTJDG, 1 XMNCP, 6 MZWV, 1 RJRHP => 6 FHTLT +15 XDBXC, 2 LTCX, 1 VRPVC => 6 ZLQW +13 WPTQ, 10 LTCX, 3 RJRHP, 14 XMNCP, 2 MZWV, 1 ZLQW => 1 ZDVW +5 BMBT => 4 WPTQ +189 ORE => 9 KTJDG +1 MZWV, 17 XDBXC, 3 XCVML => 2 XMNCP +12 VRPVC, 27 CNZTR => 2 XDBXC +15 KTJDG, 12 BHXH => 5 XCVML +3 BHXH, 2 VRPVC => 7 MZWV +121 ORE => 7 VRPVC +7 XCVML => 6 RJRHP +5 BHXH, 4 VRPVC => 5 LTCX +</code></pre></li> +</ul> +<p>Given the list of reactions in your puzzle input, <em>what is the minimum amount of <code>ORE</code> required to produce exactly 1 <code>FUEL</code>?</em></p> +</article> +<p>Your puzzle answer was <code>598038</code>.</p><article class="day-desc"><h2 id="part2">--- Part Two ---</h2><p>After collecting <code>ORE</code> for a while, you check your cargo hold: <em>1 trillion</em> (<em>1000000000000</em>) units of <code>ORE</code>.</p> +<p><em>With that much ore</em>, given the examples above:</p> +<ul> +<li>The 13312 <code>ORE</code>-per-<code>FUEL</code> example could produce <em>82892753</em> <code>FUEL</code>.</li> +<li>The 180697 <code>ORE</code>-per-<code>FUEL</code> example could produce <em>5586022</em> <code>FUEL</code>.</li> +<li>The 2210736 <code>ORE</code>-per-<code>FUEL</code> example could produce <em>460664</em> <code>FUEL</code>.</li> +</ul> +<p>Given 1 trillion <code>ORE</code>, <em>what is the maximum amount of <code>FUEL</code> you can produce?</em></p> +</article> +<p>Your puzzle answer was <code>2269325</code>.</p><p class="day-success">Both parts of this puzzle are complete! They provide two gold stars: **</p> +<p>At this point, you should <a href="/2019">return to your Advent calendar</a> and try another puzzle.</p> +<p>If you still want to see it, you can <a href="14/input" target="_blank">get your puzzle input</a>.</p> +<p>You can also <span class="share">[Share<span class="share-content">on + <a href="https://twitter.com/intent/tweet?text=I%27ve+completed+%22Space+Stoichiometry%22+%2D+Day+14+%2D+Advent+of+Code+2019&url=https%3A%2F%2Fadventofcode%2Ecom%2F2019%2Fday%2F14&related=ericwastl&hashtags=AdventOfCode" target="_blank">Twitter</a> + <a href="javascript:void(0);" onclick="var mastodon_instance=prompt('Mastodon Instance / Server Name?'); if(typeof mastodon_instance==='string' && mastodon_instance.length){this.href='https://'+mastodon_instance+'/share?text=I%27ve+completed+%22Space+Stoichiometry%22+%2D+Day+14+%2D+Advent+of+Code+2019+%23AdventOfCode+https%3A%2F%2Fadventofcode%2Ecom%2F2019%2Fday%2F14'}else{return false;}" target="_blank">Mastodon</a +></span>]</span> this puzzle.</p> +</main> + +<!-- ga --> +<script> +(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ +(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), +m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) +})(window,document,'script','//www.google-analytics.com/analytics.js','ga'); +ga('create', 'UA-69522494-1', 'auto'); +ga('set', 'anonymizeIp', true); +ga('send', 'pageview'); +</script> +<!-- /ga --> +</body> +</html> \ No newline at end of file -- 2.43.0