This repository has been archived by the owner on Dec 25, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
day_19.py
156 lines (127 loc) · 4.28 KB
/
day_19.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
#!/bin/python3
import sys
import functools
sys.setrecursionlimit(100000)
FILE = sys.argv[1] if len(sys.argv) > 1 else "input.txt"
def calculate(blueprint, time):
ore_cost = blueprint[0]
clay_cost = blueprint[1]
obs_cost = blueprint[2]
geo_cost = blueprint[3]
# Prune some situations because this seems to work...?
max_ore_cost = max(ore_cost, clay_cost, obs_cost[0], geo_cost[0]) * 2
@functools.cache
def calculate_geodes(
time_left,
ores,
clay,
obsidian,
o_bot,
c_bot,
ob_bot,
):
if time_left <= 0:
return 0
new_ores = ores + o_bot
new_clay = clay + c_bot
new_obs = obsidian + ob_bot
# What if we don't build a bot?
best = 0
# Can we build a bot? We assume that if we can make a geode bot, we
# probably want it ASAP.
if ores >= geo_cost[0] and obsidian >= geo_cost[1]:
best = max(
best,
(time_left - 1)
+ calculate_geodes(
time_left - 1,
new_ores - geo_cost[0],
new_clay,
new_obs - geo_cost[1],
o_bot,
c_bot,
ob_bot,
),
)
else:
if ores >= ore_cost:
best = max(
best,
calculate_geodes(
time_left - 1,
new_ores - ore_cost,
new_clay,
new_obs,
o_bot + 1,
c_bot,
ob_bot,
),
)
if ores >= clay_cost:
best = max(
best,
calculate_geodes(
time_left - 1,
new_ores - clay_cost,
new_clay,
new_obs,
o_bot,
c_bot + 1,
ob_bot,
),
)
if ores >= obs_cost[0] and clay >= obs_cost[1]:
best = max(
best,
calculate_geodes(
time_left - 1,
new_ores - obs_cost[0],
new_clay - obs_cost[1],
new_obs,
o_bot,
c_bot,
ob_bot + 1,
),
)
# A very sketchy assumption - assume that if we could have built a bot,
# that is the most optimal case. This is VERY likely not true but... works
# for my input apparently and the example.
if ores < max_ore_cost:
best = max(
best,
calculate_geodes(
time_left - 1, new_ores, new_clay, new_obs, o_bot, c_bot, ob_bot
),
)
return best
return calculate_geodes(time, 0, 0, 0, 1, 0, 0)
def part_one(blueprints):
levels = 0
for (itx, blueprint) in enumerate(blueprints):
geodes = calculate(blueprint, 24)
print(f"Geodes cracked for {itx + 1}: {geodes}")
levels += (itx + 1) * geodes
return levels
def part_two(blueprints):
levels = 1
for (itx, blueprint) in enumerate(blueprints[0:3]):
geodes = calculate(blueprint, 32)
print(f"Geodes cracked for {itx + 1}: {geodes}")
levels *= geodes
return levels
def main():
print(f"Using file {FILE}")
with open(FILE, "r", encoding="utf-8") as f:
blueprints = []
for line in f:
sentences = line.split(":")[1].split(".")
ore_cost = int(sentences[0].strip().split(" ")[4])
clay_cost = int(sentences[1].strip().split(" ")[4])
tmp = sentences[2].strip().split(" ")
obsidian_cost = (int(tmp[4]), int(tmp[7]))
tmp = sentences[3].strip().split(" ")
geode_cost = (int(tmp[4]), int(tmp[7]))
blueprints.append((ore_cost, clay_cost, obsidian_cost, geode_cost))
print(f"Part one: {part_one(blueprints)}")
print(f"Part two: {part_two(blueprints)}")
main()