diff --git a/2019/day14.py b/2019/day14.py index 47127e0..22ed4d6 100644 --- a/2019/day14.py +++ b/2019/day14.py @@ -1,22 +1,34 @@ +import collections import math import re +EX1 = [ + "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", +] + + def main(): with open("day14.txt", "rt") as input_file: lines = [line.rstrip() for line in input_file.readlines()] line_re = re.compile(r"(.+) => (.+)") - raw_transmos = [line_re.match(line).groups() for line in lines] - transmos = {} - for inputs, outputs in raw_transmos: + raw_reactions = [line_re.match(line).groups() for line in lines] + reactions = {} + for inputs, outputs in raw_reactions: mult, result = outputs.split(" ") input_comps = [i.split(" ") for i in inputs.split(", ")] input_tuples = [(int(q), n) for q, n in input_comps] - transmos[result] = int(mult), input_tuples + reactions[result] = int(mult), input_tuples # Part 1 - ore_per_full = get_required_ore(transmos, "FUEL", 1, {}) + ore_per_full = get_required_ore(reactions, 1) print("Required ore for 1 FUEL:", ore_per_full) + return # Part 2 # Input gives 397771 OPF. @@ -30,7 +42,7 @@ def main(): # 10^12 / x / 397771 = 0.985 -> x = 2552294 # Now on to our search. - fuel = 2552294 + fuel_q = 2552294 cursor = 10000 last_result = 0 min_target = 10**12 - ore_per_full @@ -38,8 +50,8 @@ def main(): was_below = False was_above = False while last_result not in range(min_target, max_target): - last_result = get_required_ore(transmos, "FUEL", fuel, {}) - print("{} FUEL requires {} ORE.".format(fuel, last_result)) + last_result = get_required_ore(reactions, fuel_q) + print("{} FUEL requires {} ORE.".format(fuel_q, last_result)) if last_result < min_target: if was_above: cursor /= 2 @@ -49,30 +61,34 @@ def main(): cursor /= 2 fuel -= cursor -def get_required_ore(transmos, name, quantity, leftovers): - if name == "ORE": - return quantity - - mult, comps = transmos[name] - num_reactions = math.ceil(quantity / mult) - - created = 0 - if name in leftovers: - created += leftovers[name] - leftovers[name] = 0 - - req_ore = 0 - for _ in range(num_reactions): - if created >= quantity: - break - req_ore += sum(get_required_ore(transmos, rn, rq, leftovers) for rq, rn in comps) - created += mult - - if created > quantity: - leftover = created - quantity - leftovers[name] = leftovers.get(name, 0) + leftover - - return req_ore +def get_required_ore(reactions, quantity): + stored_map = collections.defaultdict(int) + needs = [("FUEL", quantity)] + ore_per_full = 0 + while needs: + needed, needed_q = needs.pop(0) + print(f"Need {needed_q} {needed}.") + if needed == "ORE": + print(f"- {needed_q} ORE required.") + ore_per_full += needed_q + continue + react_mult, subcomps = reactions[needed] + if stored_map[needed]: + print(f"- Already got {stored_map[needed]} in storage.") + needed_q -= stored_map[needed] + stored_map[needed] = 0 + num_reacts = math.ceil(needed_q / react_mult) + print(f"- Requires {num_reacts} reaction(s) ({react_mult} {needed} per R)") + if num_reacts: + new_needs = [(name_sc, num_sc * num_reacts) for num_sc, name_sc in subcomps] + print(f"- New needs: {new_needs}") + needs += new_needs + produced = react_mult * num_reacts + print(f"- Produced {produced} {needed}.") + if produced - needed_q > 0: + print(f"- Stored {produced - needed_q} {needed} leftovers.") + stored_map[needed] += produced - needed_q + return ore_per_full if __name__ == "__main__":