-
Notifications
You must be signed in to change notification settings - Fork 0
/
day14.py
159 lines (138 loc) · 5.19 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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# vi: set shiftwidth=4 tabstop=4 expandtab:
import datetime
import os
import collections
import fractions
import math
top_dir = os.path.dirname(os.path.abspath(__file__)) + "/../../"
def get_quantity_and_chemical(s):
nb, chem = s.split(" ")
return (int(nb), chem)
def get_reaction_from_line(l):
left, mid, right = l.strip().partition(" => ")
assert mid == " => "
return (
[get_quantity_and_chemical(chunk) for chunk in left.split(", ")],
get_quantity_and_chemical(right),
)
def get_reactions_from_file(file_path=top_dir + "resources/year2019_day14_input.txt"):
with open(file_path) as f:
return [get_reaction_from_line(l) for l in f]
def apply_reaction(products, reaction_by_output, integer_recipe):
for prod, nb in products.items():
if nb > 0:
if prod in reaction_by_output:
(
chemicals_in,
nb_out,
) = reaction_by_output[prod]
if integer_recipe:
q = math.ceil(nb / nb_out)
else:
q = fractions.Fraction(nb, nb_out)
products[prod] = nb - nb_out * q
for n, chem in chemicals_in:
products[chem] += q * n
return True
return False
def ore_to_make_product(reactions, integer_recipe=True, product=[(1, "FUEL")]):
reaction_by_output = dict()
for chemicals_in, (nb_out, chem_out) in reactions:
assert chem_out not in reaction_by_output
reaction_by_output[chem_out] = (chemicals_in, nb_out)
products = collections.Counter({prod: nb for nb, prod in product})
while apply_reaction(products, reaction_by_output, integer_recipe):
pass
for prod, nb in products.items():
assert prod == "ORE" or nb <= 0
return products["ORE"]
def max_fuel_prod(reactions, ore=1000000000000):
ore_per_fuel = ore_to_make_product(reactions, False)
fuel_estimation = int(ore / ore_per_fuel)
assert ore_to_make_product(reactions, False, [(fuel_estimation, "FUEL")]) <= ore
return fuel_estimation
def run_tests():
reactions = [
"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",
]
reactions = [get_reaction_from_line(l) for l in reactions]
assert ore_to_make_product(reactions) == 31
reactions = [
"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",
]
reactions = [get_reaction_from_line(l) for l in reactions]
assert ore_to_make_product(reactions) == 165
reactions = [
"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",
]
reactions = [get_reaction_from_line(l) for l in reactions]
assert ore_to_make_product(reactions) == 13312
assert max_fuel_prod(reactions) == 82892753
reactions = [
"2 VPVL, 7 FWMGM, 2 CXFTF, 11 MNCFX => 1 STKFG",
"17 NVRVD, 3 JNWZP => 8 VPVL",
"53 STKFG, 6 MNCFX, 46 VJHF, 81 HVMC, 68 CXFTF, 25 GNMV => 1 FUEL",
"22 VJHF, 37 MNCFX => 5 FWMGM",
"139 ORE => 4 NVRVD",
"144 ORE => 7 JNWZP",
"5 MNCFX, 7 RFSQX, 2 FWMGM, 2 VPVL, 19 CXFTF => 3 HVMC",
"5 VJHF, 7 MNCFX, 9 VPVL, 37 CXFTF => 6 GNMV",
"145 ORE => 6 MNCFX",
"1 NVRVD => 8 CXFTF",
"1 VJHF, 6 MNCFX => 4 RFSQX",
"176 ORE => 6 VJHF",
]
reactions = [get_reaction_from_line(l) for l in reactions]
assert ore_to_make_product(reactions) == 180697
assert max_fuel_prod(reactions) == 5586022
reactions = [
"171 ORE => 8 CNZTR",
"7 ZLQW, 3 BMBT, 9 XCVML, 26 XMNCP, 1 WPTQ, 2 MZWV, 1 RJRHP => 4 PLWSL",
"114 ORE => 4 BHXH",
"14 VRPVC => 6 BMBT",
"6 BHXH, 18 KTJDG, 12 WPTQ, 7 PLWSL, 31 FHTLT, 37 ZDVW => 1 FUEL",
"6 WPTQ, 2 BMBT, 8 ZLQW, 18 KTJDG, 1 XMNCP, 6 MZWV, 1 RJRHP => 6 FHTLT",
"15 XDBXC, 2 LTCX, 1 VRPVC => 6 ZLQW",
"13 WPTQ, 10 LTCX, 3 RJRHP, 14 XMNCP, 2 MZWV, 1 ZLQW => 1 ZDVW",
"5 BMBT => 4 WPTQ",
"189 ORE => 9 KTJDG",
"1 MZWV, 17 XDBXC, 3 XCVML => 2 XMNCP",
"12 VRPVC, 27 CNZTR => 2 XDBXC",
"15 KTJDG, 12 BHXH => 5 XCVML",
"3 BHXH, 2 VRPVC => 7 MZWV",
"121 ORE => 7 VRPVC",
"7 XCVML => 6 RJRHP",
"5 BHXH, 4 VRPVC => 5 LTCX",
]
reactions = [get_reaction_from_line(l) for l in reactions]
assert ore_to_make_product(reactions) == 2210736
assert max_fuel_prod(reactions) == 460664
def get_solutions():
reactions = get_reactions_from_file()
print(ore_to_make_product(reactions) == 261960)
print(max_fuel_prod(reactions) == 4366186)
if __name__ == "__main__":
begin = datetime.datetime.now()
run_tests()
get_solutions()
end = datetime.datetime.now()
print(end - begin)