-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday18.py
106 lines (94 loc) · 2.47 KB
/
day18.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
import heapq
import textwrap
import re
def part1(input: str, w, h, walls_count):
walls = set(parse_input(input)[:walls_count])
maze = {
'walls': walls,
'width': w,
'height': h,
'start': (0, 0),
'target': (w - 1, h - 1),
}
return find_paths(maze)
def part2(input: str, w, h):
walls = parse_input(input)
for i in range(len(walls)):
maze = {
'walls': set(walls[:i]),
'width': w,
'height': h,
'start': (0, 0),
'target': (w - 1, h - 1),
}
path = find_paths(maze)
print(i, path, walls[:i][-1] if i > 0 else None)
if path is None:
return walls[i - 1]
def parse_input(input: str):
result = []
for line in input.splitlines():
(x, y) = line.split(',')
result.append((int(x), int(y)))
return result
def find_paths(maze):
costs = {
maze['start']: 0
}
def best_cost(pos):
return abs(maze['target'][0] - pos[0]) + abs(maze['target'][1] - pos[1])
queue = [(best_cost(maze['start']), 0, maze['start'])]
while queue:
(best_estimate, cost, pos) = heapq.heappop(queue)
if maze['target'] in costs and costs[maze['target']] < best_estimate:
break
for n in neighbors(maze, pos):
if n in costs:
if costs[n] <= cost + 1:
continue
costs[n] = cost + 1
queue.append((best_cost(n) + cost + 1, cost + 1, n))
return costs[maze['target']] if maze['target'] in costs else None
def neighbors(maze, pos):
return [
n for n in [
(pos[0] - 1, pos[1]),
(pos[0], pos[1] - 1),
(pos[0], pos[1] + 1),
(pos[0] + 1, pos[1]),
]
if n[0] >= 0 and n[0] < maze['width'] and n[1] >= 0 and n[1] < maze['height'] and n not in maze['walls']
]
if __name__ == "__main__":
test_input1 = textwrap.dedent("""
5,4
4,2
4,5
3,0
2,1
6,3
2,4
1,5
0,6
3,3
2,6
5,1
1,2
5,5
2,5
6,5
1,4
0,4
6,4
1,1
6,1
1,0
0,5
1,6
2,0
""").strip()
input = open("day18.txt").read()
print(f"Part 1 test, 22 expected: {part1(test_input1, w=7, h=7, walls_count=12)}")
print(f"Part 1: {part1(input, w=71, h=71, walls_count=1024)}")
print(f"Part 1 test, (6,1) expected: {part2(test_input1, w=7, h=7)}")
print(f"Part 2: {part2(input, w=71, h=71)}")