From fa89caacbfeb23cddf93cf1086e63c68bc9023c4 Mon Sep 17 00:00:00 2001 From: Akumatic Date: Sat, 14 Dec 2019 20:32:51 +0100 Subject: [PATCH] Added 2019 day 14 part 1 --- 2019/14/README.md | 115 +++++++++++++++++++++++++++++++++++++++++++ 2019/14/code.py | 66 +++++++++++++++++++++++++ 2019/14/input.txt | 58 ++++++++++++++++++++++ 2019/14/solution.txt | 1 + 4 files changed, 240 insertions(+) create mode 100644 2019/14/README.md create mode 100644 2019/14/code.py create mode 100644 2019/14/input.txt create mode 100644 2019/14/solution.txt diff --git a/2019/14/README.md b/2019/14/README.md new file mode 100644 index 0000000..566da87 --- /dev/null +++ b/2019/14/README.md @@ -0,0 +1,115 @@ +# 2019 Day 14: Space Stoichiometry +Copyright (c) Eric Wastl +#### [Direct Link](https://adventofcode.com/2019/day/14) + +## Part 1 + +As you approach the rings of Saturn, your ship's **low fuel** indicator turns on. There isn't any fuel here, but the rings have plenty of raw material. Perhaps your ship's Inter-Stellar Refinery Union brand **nanofactory** can turn these raw materials into fuel. + +You ask the nanofactory to produce a list of the **reactions** it can perform that are relevant to this process (your puzzle input). Every reaction turns some quantities of specific **input chemicals** into some quantity of an **output chemical**. Almost every **chemical** is produced by exactly one reaction; the only exception, `ORE`, is the raw material input to the entire process and is not produced by a reaction. + +You just need to know how much **`ORE`** you'll need to collect before you can produce one unit of **`FUEL`**. + +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 `1 A, 2 B, 3 C => 2 D` means that exactly 2 units of chemical `D` can be produced by consuming exactly 1 `A`, 2 `B` and 3 `C`. You can run the full reaction as many times as necessary; for example, you could produce 10 `D` by consuming 5 `A`, 10 `B`, and 15 `C`. + +Suppose your nanofactory produces the following list of reactions: + +``` +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 +``` + +The first two reactions use only `ORE` as inputs; they indicate that you can produce as much of chemical `A` as you want (in increments of 10 units, each 10 costing 10 `ORE`) and as much of chemical `B` as you want (each costing 1 `ORE`). To produce 1 `FUEL`, a total of **31** `ORE` is required: 1 `ORE` to produce 1 `B`, then 30 more `ORE` to produce the 7 + 7 + 7 + 7 = 28 `A` (with 2 extra `A` wasted) required in the reactions to convert the `B` into `C`, `C` into `D`, `D` into `E`, and finally `E` into `FUEL`. (30 `A` is produced because its reaction requires that it is created in increments of 10.) + +Or, suppose you have the following list of reactions: + +``` +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 +``` + +The above list of reactions requires **165** `ORE` to produce 1 `FUEL`: + +- Consume 45 `ORE` to produce 10 `A`. +- Consume 64 `ORE` to produce 24 `B`. +- Consume 56 `ORE` to produce 40 `C`. +- Consume 6 `A`, 8 `B` to produce 2 `AB`. +- Consume 15 `B`, 21 `C` to produce 3 `BC`. +- Consume 16 `C`, 4 `A` to produce 4 `CA`. +- Consume 2 `AB`, 3 `BC`, 4 `CA` to produce 1 `FUEL`. + +Here are some larger examples: + +- **13312** `ORE` for 1 `FUEL`: + + ``` + 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 + ``` + +- **180697** ORE for 1 FUEL: + ``` + 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 + ``` + +- **2210736** ORE for 1 FUEL: + ``` + 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 + ``` + +Given the list of reactions in your puzzle input, **what is the minimum amount of `ORE` required to produce exactly 1 `FUEL`**? + +## Part 2 + +After collecting `ORE` for a while, you check your cargo hold: **1 trillion** (**1000000000000**) units of `ORE`. + +**With that much ore**, given the examples above: + +- The 13312 `ORE`-per-`FUEL` example could produce **82892753** `FUEL`. +- The 180697 `ORE`-per-`FUEL` example could produce **5586022** `FUEL`. +- The 2210736 `ORE`-per-`FUEL` example could produce **460664** `FUEL`. + +Given 1 trillion `ORE`, **what is the maximum amount of FUEL you can produce**? \ No newline at end of file diff --git a/2019/14/code.py b/2019/14/code.py new file mode 100644 index 0000000..75bfa28 --- /dev/null +++ b/2019/14/code.py @@ -0,0 +1,66 @@ +""" https://adventofcode.com/2019/day/14 """ + +def readFile(): + with open(f"{__file__.rstrip('code.py')}input.txt", "r") as f: + return [line[:-1] for line in f.readlines()] + +class Factory: + def __init__(self): + self.recipes = dict() + self.storage = {"ORE": 0} + self.ores = 0 + + def addRecipe(self, recipe): + left, right = recipe.split(" => ") + left, right = left.split(", "), right.split() + self.storage[right[1]] = 0 + self.recipes[right[1]] = {"amount": int(right[0]), "req": {}} + for l in left: + l = l.split() + self.recipes[right[1]]["req"][l[1]] = int(l[0]) + + def produce(self, chem="FUEL"): + if "ORE" in self.recipes[chem]["req"]: + cur = self.storage["ORE"] + while self.storage["ORE"] < self.recipes[chem]["req"]["ORE"]: + self.storage["ORE"] += self.recipes[chem]["req"]["ORE"] + self.ores += self.recipes[chem]["req"]["ORE"] + self.storage[chem] += self.recipes[chem]["amount"] + self.storage["ORE"] -= self.recipes[chem]["req"]["ORE"] + + else: + for r in self.recipes[chem]["req"]: + while self.storage[r] < self.recipes[chem]["req"][r]: + self.produce(r) + self.storage[chem] += self.recipes[chem]["amount"] + for r in self.recipes[chem]["req"]: + self.storage[r] -= self.recipes[chem]["req"][r] + while self.storage[r] < 0: + self.produce(r) + return + +def part1(vals): + factory = Factory() + for val in vals: + factory.addRecipe(val) + factory.produce() + return factory.ores + +def part2(vals): + pass + +def test(): + assert part1(["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"]) == 31 + assert part1(["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"]) == 165 + assert part1(["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"]) == 13312 + +if __name__ == "__main__": + test() + vals = readFile() + print(f"Part 1: {part1(vals)}") + print(f"Part 2: {part2(vals)}") \ No newline at end of file diff --git a/2019/14/input.txt b/2019/14/input.txt new file mode 100644 index 0000000..a0c105f --- /dev/null +++ b/2019/14/input.txt @@ -0,0 +1,58 @@ +1 JKXFH => 8 KTRZ +11 TQGT, 9 NGFV, 4 QZBXB => 8 MPGLV +8 NPDPH, 1 WMXZJ => 7 VCNSK +1 MPGLV, 6 CWHX => 5 GDRZ +16 JDFQZ => 2 CJTB +1 GQNQF, 4 JDFQZ => 5 WJKDC +2 TXBS, 4 SMGQW, 7 CJTB, 3 NTBQ, 13 CWHX, 25 FLPFX => 1 FUEL +3 WMXZJ, 14 CJTB => 5 FLPFX +7 HDCTQ, 1 MPGLV, 2 VFVC => 1 GSVSD +1 WJKDC => 2 NZSQR +1 RVKLC, 5 CMJSL, 16 DQTHS, 31 VCNSK, 1 RKBMX, 1 GDRZ => 8 SMGQW +2 JDFQZ, 2 LGKHR, 2 NZSQR => 9 TSWN +34 LPXW => 8 PWJFD +2 HDCTQ, 2 VKWN => 8 ZVBRF +2 XCTF => 3 QZBXB +12 NGFV, 3 HTRWR => 5 HDCTQ +1 TSWN, 2 WRSD, 1 ZVBRF, 1 KFRX, 5 BPVMR, 2 CLBG, 22 NPSLQ, 9 GSVSD => 5 NTBQ +10 TSWN => 9 VFVC +141 ORE => 6 MKJDZ +4 NPSLQ, 43 VCNSK, 4 PSJL, 14 KTRZ, 3 KWCDP, 3 HKBS, 11 WRSD, 3 MXWHS => 8 TXBS +8 VCNSK, 1 HDCTQ => 7 MXWHS +3 JDFQZ, 2 GQNQF => 4 XJSQW +18 NGFV, 4 GSWT => 5 KFRX +2 CZSJ => 7 GMTW +5 PHKL, 5 VCNSK, 25 GSVSD => 8 FRWC +30 FRWC, 17 GKDK, 8 NPSLQ => 3 CLBG +8 MXWHS, 3 SCKB, 2 NPSLQ => 1 JKXFH +1 XJSQW, 7 QZBXB => 1 LGKHR +115 ORE => 6 GQNQF +12 HTRWR, 24 HDCTQ => 1 RKBMX +1 DQTHS, 6 XDFWD, 1 MXWHS => 8 VKWN +129 ORE => 3 XCTF +6 GQNQF, 7 WJKDC => 5 PHKL +3 NZSQR => 2 LPXW +2 FLPFX, 1 MKLP, 4 XDFWD => 8 NPSLQ +4 DQTHS, 1 VKWN => 1 BPVMR +7 GMTW => 1 TXMVX +152 ORE => 8 JDFQZ +21 LGKHR => 9 NPDPH +5 CJTB, 1 QZBXB, 3 KFRX => 1 GTPB +1 MXWHS => 3 CWHX +3 PHKL => 1 NGFV +1 WMXZJ => 7 XDFWD +3 TSWN, 1 VKWN => 8 GKDK +1 ZVBRF, 16 PWJFD => 8 CMJSL +3 VCNSK, 7 GDRZ => 4 HKBS +20 XJSQW, 6 HTRWR, 7 CJTB => 5 WMXZJ +12 ZVBRF, 10 FRWC, 12 TSWN => 4 WRSD +16 HDCTQ, 3 GTPB, 10 NGFV => 4 KWCDP +3 TXMVX, 1 NPDPH => 8 HTRWR +9 NPDPH, 6 LPXW => 8 GSWT +4 MKLP => 1 TQGT +34 GTPB => 3 RVKLC +25 VFVC, 5 RVKLC => 8 DQTHS +7 KWCDP => 3 SCKB +6 LGKHR => 8 MKLP +39 MKJDZ => 9 CZSJ +2 TSWN, 1 WMXZJ => 3 PSJL diff --git a/2019/14/solution.txt b/2019/14/solution.txt new file mode 100644 index 0000000..711a42a --- /dev/null +++ b/2019/14/solution.txt @@ -0,0 +1 @@ +Part 1: 2486514 \ No newline at end of file