Skip to content

Commit f16a8ad

Browse files
committed
Add day 21, 2024
1 parent 4367b17 commit f16a8ad

File tree

1 file changed

+135
-0
lines changed

1 file changed

+135
-0
lines changed

2024/day21/solution.py

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
import networkx as nx
2+
from itertools import product
3+
from functools import cache
4+
5+
codes = """286A
6+
480A
7+
140A
8+
413A
9+
964A""".split("\n")
10+
11+
kp_num = nx.grid_2d_graph(3, 4)
12+
kp_num.remove_node((0, 0))
13+
14+
mapping = {
15+
(0, 1): "1",
16+
(0, 2): "4",
17+
(0, 3): "7",
18+
(1, 0): "0",
19+
(1, 1): "2",
20+
(1, 2): "5",
21+
(1, 3): "8",
22+
(2, 0): "A",
23+
(2, 1): "3",
24+
(2, 2): "6",
25+
(2, 3): "9"
26+
}
27+
28+
kp_num = nx.relabel_nodes(kp_num, mapping)
29+
30+
kp_num_moves = {
31+
("A", "0"): "<",
32+
("0", "A"): ">",
33+
("A", "3"): "^",
34+
("3", "A"): "v",
35+
("0", "2"): "^",
36+
("2", "0"): "v",
37+
("3", "2"): "<",
38+
("2", "3"): ">",
39+
("3", "6"): "^",
40+
("6", "3"): "v",
41+
("2", "1"): "<",
42+
("1", "2"): ">",
43+
("2", "5"): "^",
44+
("5", "2"): "v",
45+
("1", "4"): "^",
46+
("4", "1"): "v",
47+
("6", "5"): "<",
48+
("5", "6"): ">",
49+
("6", "9"): "^",
50+
("9", "6"): "v",
51+
("5", "4"): "<",
52+
("4", "5"): ">",
53+
("5", "8"): "^",
54+
("8", "5"): "v",
55+
("4", "7"): "^",
56+
("7", "4"): "v",
57+
("9", "8"): "<",
58+
("8", "9"): ">",
59+
("8", "7"): "<",
60+
("7", "8"): ">"
61+
}
62+
63+
kp_dir = nx.grid_2d_graph(3, 2)
64+
kp_dir.remove_node((0, 1))
65+
66+
mapping = {
67+
(0, 0): "<",
68+
(1, 0): "v",
69+
(2, 0): ">",
70+
(1, 1): "^",
71+
(2, 1): "A"
72+
}
73+
74+
kp_dir = nx.relabel_nodes(kp_dir, mapping)
75+
76+
kp_dir_moves = {
77+
(">", "v"): "<",
78+
("v", ">"): ">",
79+
(">", "A"): "^",
80+
("A", ">"): "v",
81+
("v", "<"): "<",
82+
("<", "v"): ">",
83+
("v", "^"): "^",
84+
("^", "v"): "v",
85+
("A", "^"): "<",
86+
("^", "A"): ">"
87+
}
88+
89+
90+
def get_num_inputs(output):
91+
inputs = []
92+
for x, y in zip("A" + output, output):
93+
sub_inputs = []
94+
paths = nx.all_shortest_paths(kp_num, x, y)
95+
for path in paths:
96+
sub_inputs.append("".join(kp_num_moves[(u, v)] for u, v in zip(path, path[1:])) + "A")
97+
inputs.append(sub_inputs)
98+
99+
return [''.join(s) for s in product(*inputs)]
100+
101+
102+
def get_dir_inputs(output):
103+
inputs = []
104+
for x, y in zip("A" + output, output):
105+
sub_inputs = []
106+
paths = nx.all_shortest_paths(kp_dir, x, y)
107+
for path in paths:
108+
sub_inputs.append("".join(kp_dir_moves[(u, v)] for u, v in zip(path, path[1:])) + "A")
109+
inputs.append(sub_inputs)
110+
return [''.join(s) for s in product(*inputs)]
111+
112+
113+
@cache
114+
def min_length(buttons, n):
115+
if n == 0:
116+
return len(buttons)
117+
assert buttons[-1] == "A"
118+
if buttons.count("A") > 1:
119+
ls = [x + "A" for x in buttons.split("A")][:-1]
120+
return sum(min_length(pt, n) for pt in ls)
121+
else:
122+
return min(min_length(x, n - 1) for x in get_dir_inputs(buttons))
123+
124+
125+
def complexity(code, n):
126+
seqs = get_num_inputs(code)
127+
min_len = min(min_length(seq, n) for seq in seqs)
128+
return min_len*int(code[:-1])
129+
130+
131+
# Part 1
132+
print(sum(complexity(code, 2) for code in codes))
133+
134+
# Part 2
135+
print(sum(complexity(code, 25) for code in codes))

0 commit comments

Comments
 (0)