-
Notifications
You must be signed in to change notification settings - Fork 0
/
day19.py
100 lines (77 loc) · 3.69 KB
/
day19.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
from typing import Any
import mip as mip # type: ignore
from parse import parse # type: ignore
import utils
bprints = utils.load_input("day19")
def check_blueprint(mins: int, blueprint: dict[str, int]) -> int:
model = mip.Model(sense=mip.MAXIMIZE)
obj = mip.LinExpr(0) # type: ignore
vars_all: list[dict[str, Any]] = []
for m in range(mins):
vars: dict[str, Any] = {}
vars.update({"ore": model.add_var(f"ore_{m}", var_type=mip.BINARY)})
vars.update({"clay": model.add_var(f"clay_{m}", var_type=mip.BINARY)})
vars.update({"obs": model.add_var(f"obs_{m}", var_type=mip.BINARY)})
vars.update({"geo": model.add_var(f"geo_{m}", var_type=mip.BINARY)})
vars_all.append(vars)
model.add_constr(vars["ore"] + vars["clay"] + vars["obs"] + vars["geo"] <= 1) # type: ignore
ore = mip.LinExpr(const=m) # type: ignore
clay = mip.LinExpr(const=0) # type: ignore
obs = mip.LinExpr(const=0) # type: ignore
for m_ in range(m):
ore.add_var(vars_all[m_]["ore"], m - m_ - 1) # type: ignore
ore.add_var(vars_all[m_]["ore"], -blueprint["oror"]) # type: ignore
ore.add_var(vars_all[m_]["clay"], -blueprint["clor"]) # type: ignore
ore.add_var(vars_all[m_]["obs"], -blueprint["obor"]) # type: ignore
ore.add_var(vars_all[m_]["geo"], -blueprint["geor"]) # type: ignore
clay.add_var(vars_all[m_]["clay"], m - m_ - 1) # type: ignore
clay.add_var(vars_all[m_]["obs"], -blueprint["obcl"]) # type: ignore
obs.add_var(vars_all[m_]["obs"], m - m_ - 1) # type: ignore
obs.add_var(vars_all[m_]["geo"], -blueprint["geob"]) # type: ignore
model.add_constr( # type: ignore
ore
>= vars["ore"] * blueprint["oror"]
+ vars["clay"] * blueprint["clor"]
+ vars["obs"] * blueprint["obor"]
+ vars["geo"] * blueprint["geor"]
)
model.add_constr(clay >= vars["obs"] * blueprint["obcl"]) # type: ignore
model.add_constr(obs >= vars["geo"] * blueprint["geob"]) # type: ignore
obj.add_var(vars["geo"], mins - m - 1) # type: ignore
model.objective = obj
model.verbose = 0
model.optimize()
return int(model.objective_value) # type: ignore
def part1(text: str) -> int:
mins = 24
blueprints: list[dict[str, int]] = []
score: list[int] = []
for l in text.splitlines():
vars = parse(
"Blueprint {i}: Each ore robot costs {oror} ore. Each clay robot costs {clor} ore. Each obsidian robot costs {obor} ore and {obcl} clay. Each geode robot costs {geor} ore and {geob} obsidian.",
l.strip(),
)
if vars is not None:
blueprints.append({k: int(v) for k, v in vars.named.items()}) # type: ignore
for blueprint in blueprints:
val = check_blueprint(mins, blueprint)
score.append(val * blueprint["i"])
return sum(score)
def part2(text: str) -> int:
mins = 32
blueprints: list[dict[str, int]] = []
score: list[int] = []
for l in text.splitlines():
vars = parse(
"Blueprint {i}: Each ore robot costs {oror} ore. Each clay robot costs {clor} ore. Each obsidian robot costs {obor} ore and {obcl} clay. Each geode robot costs {geor} ore and {geob} obsidian.",
l.strip(),
)
if vars is not None:
blueprints.append({k: int(v) for k, v in vars.named.items()}) # type: ignore
for blueprint in blueprints[:3]:
val = check_blueprint(mins, blueprint)
score.append(val)
return score[0] * score[1] * score[2]
if __name__ == "__main__":
print(part1(bprints))
print(part2(bprints))