-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday14.py
55 lines (45 loc) · 1.59 KB
/
day14.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
from collections import namedtuple, defaultdict, deque
from math import ceil
from helpers import read_input
Chemical = namedtuple('Chemical', ['amount', 'name'])
Equation = namedtuple('Equation', ['produced', 'ingredients'])
def parse_line(line):
to_chemical = lambda x: Chemical(int(x[0]), x[1])
ins, out = line.split(" => ")
ins = frozenset(map(to_chemical, map(str.split, ins.split(', '))))
out = to_chemical(out.split())
return (out.name, Equation(out.amount, ins))
def needed_ore(equations, amount=1):
surpluses = defaultdict(int)
queue = deque([Chemical(amount, "FUEL")])
res = 0
while queue:
amount, name = queue.popleft()
surplus = surpluses[name]
missing = amount - surplus
if name == 'ORE':
res += missing
else:
produced, ingredients = equations[name]
needed_reactions = ceil(missing / produced)
surplus = needed_reactions * produced - missing
surpluses[name] = surplus
for chem in ingredients:
queue.append(Chemical(needed_reactions * chem.amount, chem.name))
return res
def part2(equations, start):
TRILLION = 1_000_000_000_000
lo = TRILLION // start
hi = 2 * lo
while lo < hi - 1:
mid = (lo + hi) // 2
ore = needed_ore(equations, mid)
if ore < TRILLION:
lo = mid
else:
hi = mid
return mid
equations = dict(parse_line(line) for line in read_input(14))
ore_for_one_fuel = needed_ore(equations)
print(ore_for_one_fuel)
print(part2(equations, ore_for_one_fuel))