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