-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathday21.py
executable file
·119 lines (93 loc) · 2.2 KB
/
day21.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
#!/usr/bin/env python3
from utils.all import *
advent.setup(2024, 21)
fin = advent.get_input()
lines = read_lines(fin)
ans1 = ans2 = 0
# +---+---+---+
# | 7 | 8 | 9 |
# +---+---+---+
# | 4 | 5 | 6 |
# +---+---+---+
# | 1 | 2 | 3 |
# +---+---+---+
# | 0 | A |
# +---+---+
class D(dict):
pass
gnums = D({
'A': ('0<', '3^'),
'0': ('A>', '2^'),
'1': ('2>', '4^'),
'2': ('0v', '1<', '3>', '5^'),
'3': ('Av', '2<', '6^'),
'4': ('1v', '5>', '7^'),
'5': ('2v', '4<', '6>', '8^'),
'6': ('3v', '5<', '9^'),
'7': ('4v', '8>'),
'8': ('5v', '7<', '9>'),
'9': ('6v', '8<'),
})
gnums.name = 'gnums'
# +---+---+
# | ^ | A |
# +---+---+---+
# | < | v | > |
# +---+---+---+
gdirs = D({
'A': ('>v', '^<'),
'^': ('A>', 'vv'),
'<': ('v>',),
'>': ('v<', 'A^'),
'v': ('<<', '>>', '^^'),
})
gdirs.name = 'gdirs'
@selective_cache('src', 'dst')
def bfs_all_paths(g, src, dst):
queue = deque([(src, '')])
distance = defaultdict(lambda: INFINITY, {src: 0})
paths = []
while queue:
node, path = queue.popleft()
if node == dst:
if len(path) <= distance[dst]:
paths.append(path)
continue
for neighbor, key in g[node]:
d = distance[node] + 1
if d > distance[dst] or d > distance[neighbor]:
continue
distance[neighbor] = d
queue.append((neighbor, path + key))
assert len(set(map(len, paths))) == 1
return paths
@cache
# @log_calls_recursive()
def solve(graph_name, code, robot, curchar='A'):
g = gdirs if graph_name == 'gdirs' else gnums
if not code:
return 0
if robot == 0:
# Just follow any path as is
res = 0
for a, b in sliding_window(curchar + code, 2):
res += len(bfs_all_paths(g, a, b)[0]) + 1
return res
# Check all possible paths I can use to get from curchar to nextchar
nextchar = code[0]
paths = bfs_all_paths(g, curchar, nextchar)
# solve.eprint(f'{curchar=} {nextchar=} {paths=}')
best = INFINITY
for path in paths:
x = solve('gdirs', path + 'A', robot - 1)
if x < best:
best = x
return best + solve(g.name, code[1:], robot, nextchar)
for code in lines:
s = solve('gnums', code, 2)
ans1 += s * int(code[:-1])
advent.print_answer(1, ans1)
for code in lines:
s = solve('gnums', code, 25)
ans2 += s * int(code[:-1])
advent.print_answer(2, ans2)