AdventOfCode/2019/day14.py

80 lines
2.4 KiB
Python

import math
import re
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:
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
# Part 1
ore_per_full = get_required_ore(transmos, "FUEL", 1, {})
print("Required ore for 1 FUEL:", ore_per_full)
# Part 2
# Input gives 397771 OPF.
# 10^12 ores with 13312 OPF example gives 82892753 FUEL.
# 10^12 ores with 180697 OPF example gives 5586022 FUEL.
# 10^12 ores with 2210736 OPF example gives 460664 FUEL.
# 10^12 / 82892753 / 13312 ~= 0.91
# 10^12 / 5586022 / 180697 ~= 0.99
# 10^12 / 460664 / 2210736 ~= 0.98
# Let's say our reaction will have this value at about 0.985.
# 10^12 / x / 397771 = 0.985 -> x = 2552294
# Now on to our search.
fuel = 2552294
cursor = 10000
last_result = 0
min_target = 10**12 - ore_per_full
max_target = 10**12
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))
if last_result < min_target:
if was_above:
cursor /= 2
fuel += cursor
elif last_result > max_target:
if was_below:
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
if __name__ == "__main__":
main()