-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathscript.py
76 lines (60 loc) · 2.22 KB
/
script.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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
from GhostyUtils import aoc
import math
from collections import defaultdict, deque
def ore_for_n_fuel(fuel: int, reactions: dict) -> int:
required = deque()
required.append(('FUEL', fuel))
leftovers = defaultdict(int)
ore = 0
# while we still have chemicals to make...
while required:
# take a chemical from the queue
product, amount = required.popleft()
# use materials from our leftover pile, if we have enough to cover the whole cost
if amount <= leftovers[product]:
leftovers[product] -= amount
continue
# use up any leftovers we might have
to_create = amount - leftovers[product]
del leftovers[product]
# calculate how many reactions we need to do
creates = reactions[product]['creates']
num_reactions = math.ceil(to_create / creates)
# add leftovers to our pile
leftover = (creates * num_reactions) - to_create
leftovers[product] += leftover
# add all the reactants to make this product to the queue
for reactant, amount in reactions[product]['reactants'].items():
# if our reactant is ore, add to the ore count instead
if reactant == 'ORE':
ore += amount * num_reactions
else:
required.append((reactant, amount * num_reactions))
return ore
def main():
reactions_txt = aoc.read_lines()
reactions = {}
for reaction in reactions_txt:
input, output = reaction.split(' => ')
inputs = input.split(', ')
amount, name = output.split()
chemicals = {name: int(amount) for amount, name in map(str.split, inputs)}
reactions[name] = {'creates': int(amount), 'reactants': chemicals}
ore = ore_for_n_fuel(1, reactions)
print('p1:', ore)
# binary search the amount of fuel we can make without going over 1e12 ore
low = 1
high = 1e12
while low < high - 1:
test = (low + high) // 2
ore = ore_for_n_fuel(test, reactions)
if ore > 1e12:
high = test
elif ore < 1e12:
low = test
else:
low = test
break
print('p2:', int(low))
if __name__ == "__main__":
main()