From 10d119a242fdbff76c69abea7d4e71a2286f2aac Mon Sep 17 00:00:00 2001 From: Tibor Bizjak Date: Tue, 14 Mar 2023 00:58:34 +0100 Subject: [PATCH] Added day 14 --- day14.py | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 day14.py diff --git a/day14.py b/day14.py new file mode 100644 index 0000000..fbea1a0 --- /dev/null +++ b/day14.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python3 + +from collections import defaultdict + +ORE = "ORE" +FUEL = "FUEL" + +class Reactor: + def __init__(self, reactions, root=ORE): + self.reactions = reactions + self.root = root + self.produced = defaultdict(int) + self.leftover = defaultdict(int) + + def produce(self, el, n): + if el == self.root: + self.produced[el] += n + return + min = self.reactions[el][el] + if type(min) == float: + k = (n + min - 1) / min + else: + k = (n + min - 1) // min + for el2, m in self.reactions[el].items(): + if el2 == el: + continue + self.get(el2, k * m) + p = k*min + self.produced[el] += p + self.leftover[el] += p - n + + def get(self, el, n): + n -= self.leftover[el] + self.leftover[el] = 0 + if n <= 0: + self.leftover[el] = -n + return + self.produce(el, n) + +def parse(line): + el = line.split()[-1] + line = line.replace(" => ", ', ') + return el, dict((m.split()[1], int(m.split()[0])) + for m in line.split(', ')) + + +def ore_per_fuel(reactions, n=1): + reactor = Reactor(reactions) + reactor.get(FUEL, n) + return reactor.produced[ORE] + +def ore_per_fuel_lim(reactions): + float_recs = {} + for el in reactions.keys(): + min = float(reactions[el][el]) + float_recs[el] = dict((el2, n/min) for el2, n in reactions[el].items()) + return ore_per_fuel(float_recs) + +def search(f, target, best): + step = best // 100 + i = best + while step > 0: + while f(i) <= target: + i += step + i -= step + step //= 10 + return i + + +def preproc(puzzle_input): + return dict(map(parse, puzzle_input.split('\n'))) + +def partI(reactions): + r = ore_per_fuel(reactions) + return r + +def partII(reactions): + ore = 10**12 + best = int(ore // ore_per_fuel_lim(reactions)) + return search(lambda n: ore_per_fuel(reactions, n), ore, best) + +from main import Tests + +tests = Tests() +tests.add( +"""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""", +partI=13312) + + +tests.add( +"""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""", +partI=180697) + +tests.add( +"""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""", +partI=2210736) +