def readfile(path):
"""Read and return file contents"""
with open(path) as input_file:
return input_file.read().strip()
testinputs = ["""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""",
"""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""",
"""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"""]
def parse_val(val):
pieces = val.split(" ")
return (pieces[1], int(pieces[0]))
def parse_line(ln):
ins, out = ln.split(" => ")
ins = map(parse_val, ins.split(", "))
out = parse_val(out)
return out, list(ins)
def process(inp):
reactions = list(map(parse_line, inp.split("\n")))
data = {}
for out, ins in reactions:
data[out[0]] = [out[1], ins]
return data
def deps(data, x, output=None):
if output is None:
output = set()
if x not in data:
return output
ins = data[x][1]
for o, val in ins:
output.add(o)
deps(data, o, output)
return output
def postprocess(data):
for out in data:
data[out].append(deps(data, out))
return data
postprocess(process(testinputs[0]))
from collections import defaultdict
import math
def get_ore(data, req={'FUEL': 1}):
rdeps = defaultdict(set)
for x, (count, total, deps) in data.items():
for dep in deps:
rdeps[dep].add(x)
spares = defaultdict(lambda: 0)
while True:
# print(req, spares)
next_req = defaultdict(lambda: 0)
active_elems = req.keys()
for elem, amt in req.items():
if elem in data and not (active_elems & rdeps.get(elem, set())):
min_amt = data[elem][0]
multiplier = math.ceil(amt / min_amt)
if spares[elem] >= amt:
spares[elem] -= amt
else:
req_amt = amt - spares[elem]
spares[elem] += multiplier * min_amt - amt
for inp, amt in data[elem][1]:
next_req[inp] += amt * multiplier
else:
next_req[elem] += amt
req = next_req
if len(next_req) == 1:
break
return req
get_ore(postprocess(process(testinputs[0])))
def f(x):
return get_ore(postprocess(process(x)))
get_ore(postprocess(process(testinputs[1])))
f(testinputs[2])
f(readfile("AoC/input14.txt"))
def max_fuel(inp, available_ore=1000000000000):
fuel = 1
used_ore = 0
while used_ore <= available_ore:
data = postprocess(process(inp))
used_ore = get_ore(data, req={'FUEL': fuel})["ORE"]
if used_ore <= available_ore:
fuel *= 2
start = fuel // 2
end = fuel
index = 0
while index <= 1000 and start != end - 1:
index += 1
mid = (start + end) // 2
used_ore = get_ore(data, req={'FUEL': mid})["ORE"]
if used_ore < available_ore:
start = mid
else:
end = mid
print(get_ore(data, req={'FUEL': start})["ORE"])
return start
max_fuel(testinputs[2])
max_fuel(readfile("AoC/input14.txt"))
I was a bit too tired and ended up falling asleep before midnight today, which means no meaningful ranks. I took the opportunity to switch out how I edit notebooks this time around, and set up EIN: Emacs-IPython-Notebooks and this seems like a magically better experience than Jupyter Lab. I can easily navigate through the full notebook, search works exactly like I would expect it to. There are of course some mild visual rough edges, but this was a really good experience otherwise.