-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathday12.py
executable file
·72 lines (52 loc) · 1.65 KB
/
day12.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
#!/usr/bin/env python3
from collections import deque
from math import inf as INFINITY
from itertools import filterfalse
import sys
def neighbors4(grid, r, c, h, w):
for nr, nc in ((r + 1, c), (r - 1, c), (r, c + 1), (r, c - 1)):
if 0 <= nr < h and 0 <= nc < w:
yield nr, nc
def neighbors_forward(grid, r, c, h, w):
max_el = grid[r][c] + 1
neigh = neighbors4(grid, r, c, h, w)
yield from ((nr, nc) for nr, nc in neigh if grid[nr][nc] <= max_el)
def neighbors_backward(grid, r, c, h, w):
min_el = grid[r][c] - 1
neigh = neighbors4(grid, r, c, h, w)
yield from ((nr, nc) for nr, nc in neigh if grid[nr][nc] >= min_el)
def bfs(grid, src, dst, get_neighbors):
h, w = len(grid), len(grid[0])
queue = deque([(0, src)])
visited = set()
while queue:
distance, rc = queue.popleft()
r, c = rc
if rc == dst or grid[r][c] == dst:
return distance
if rc not in visited:
visited.add(rc)
for n in get_neighbors(grid, r, c, h, w):
if n in visited:
continue
queue.append((distance + 1, n))
return INFINITY
# Open the first argument as input or use stdin if no arguments were given
fin = open(sys.argv[1], 'rb') if len(sys.argv) > 1 else sys.stdin.buffer
grid = list(map(list, fin.read().splitlines()))
START, END, LOWEST, HIGHEST = b'SEaz'
src = dst = None
for r, row in enumerate(grid):
for c, cell in enumerate(row):
if cell == START:
src = r, c
grid[r][c] = LOWEST
elif cell == END:
dst = r, c
grid[r][c] = HIGHEST
if src and dst:
break
min_dist = bfs(grid, src, dst, neighbors_forward)
print('Part 1:', min_dist)
min_dist_from_any_a = bfs(grid, dst, LOWEST, neighbors_backward)
print('Part 2:', min_dist_from_any_a)