-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday_12.py
124 lines (104 loc) · 4.92 KB
/
day_12.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
120
121
122
123
124
from collections import defaultdict
from dataclasses import dataclass
from typing import Optional, Dict
with open('inputs/test_day_12.txt', 'r') as f:
test_lines = [list(l.strip()) for l in f.readlines()]
with open('inputs/day_12.txt', 'r') as f:
lines = [list(l.strip()) for l in f.readlines()]
def find_pos(state, pos):
for row in range(len(state)):
for col in range(len(state[row])):
if state[row][col] == pos:
return Point(row, col)
def BFS_OF_SHAAAME(state, nr_steps, c_pos, target_pos, visited):
# morning brain implemented DFS instead of BFS, which can't actually solve for the actual input
row, col = c_pos
target_row, target_col = target_pos
if row == target_row and col == target_col:
return nr_steps
if f'{row}:{col}' in visited:
return None
current_hight = ord(state[row][col])
visited.add(f'{row}:{col}')
print(f'visiting: {c_pos}; visited: {visited}')
directions = []
if row > 0 and current_hight - ord(state[row - 1][col]) >= -1:
up = BFS_OF_SHAAAME(state, nr_steps + 1, (row - 1, col), target_pos, visited.copy())
if up is not None:
directions.append(up)
if row < len(state) - 1 and current_hight - ord(state[row + 1][col]) >= -1:
down = BFS_OF_SHAAAME(state, nr_steps + 1, (row + 1, col), target_pos, visited.copy())
if down is not None:
directions.append(down)
if col > 0 and current_hight - ord(state[row][col - 1]) >= -1:
left = BFS_OF_SHAAAME(state, nr_steps + 1, (row, col - 1), target_pos, visited.copy())
if left is not None:
directions.append(left)
if col < len(state[row]) - 1 and current_hight - ord(state[row][col + 1]) >= -1:
right = BFS_OF_SHAAAME(state, nr_steps + 1, (row, col + 1), target_pos, visited.copy())
if right is not None:
directions.append(right)
min_steps = min(directions) if directions else None
return min_steps
@dataclass(frozen=True)
class Point:
row: int
col: int
def get_traversable_neighbours_asc(state, pos):
traversable_neighbours = []
current_hight = ord(state[pos.row][pos.col])
if pos.row > 0 and current_hight - ord(state[pos.row - 1][pos.col]) >= -1:
traversable_neighbours.append(Point(pos.row - 1, pos.col))
if pos.row < len(state) - 1 and current_hight - ord(state[pos.row + 1][pos.col]) >= -1:
traversable_neighbours.append(Point(pos.row + 1, pos.col))
if pos.col > 0 and current_hight - ord(state[pos.row][pos.col - 1]) >= -1:
traversable_neighbours.append(Point(pos.row, pos.col - 1))
if pos.col < len(state[pos.row]) - 1 and current_hight - ord(state[pos.row][pos.col + 1]) >= -1:
traversable_neighbours.append(Point(pos.row, pos.col + 1))
return traversable_neighbours
def get_traversable_neighbours_desc(state, pos):
traversable_neighbours = []
current_hight = ord(state[pos.row][pos.col])
if pos.row > 0 and current_hight - ord(state[pos.row - 1][pos.col]) <= 1:
traversable_neighbours.append(Point(pos.row - 1, pos.col))
if pos.row < len(state) - 1 and current_hight - ord(state[pos.row + 1][pos.col]) <= 1:
traversable_neighbours.append(Point(pos.row + 1, pos.col))
if pos.col > 0 and current_hight - ord(state[pos.row][pos.col - 1]) <= 1:
traversable_neighbours.append(Point(pos.row, pos.col - 1))
if pos.col < len(state[pos.row]) - 1 and current_hight - ord(state[pos.row][pos.col + 1]) <= 1:
traversable_neighbours.append(Point(pos.row, pos.col + 1))
return traversable_neighbours
def dijkstra(state, start, target=None):
universe: Dict[Optional[Point, int]] = defaultdict(lambda: None)
current_pos = start
distance = 0
visited = set()
universe[current_pos] = 0
while True:
neighbours = (
get_traversable_neighbours_asc(state, current_pos) if target
else get_traversable_neighbours_desc(state, current_pos)
)
for neighbour in neighbours:
if neighbour in visited:
continue
new_distance = distance + 1
if universe[neighbour] is None or universe[neighbour] > new_distance:
universe[neighbour] = new_distance
universe[current_pos] = distance
visited.add(current_pos)
if target and current_pos == target:
return universe[target]
if target is None and state[current_pos.row][current_pos.col] == 'a':
return universe[current_pos]
candidates = [node for node in universe.items() if node[1] and node[0] not in visited]
current_pos, distance = sorted(candidates, key=lambda x: x[1])[0]
# print(f'{current_pos} - {distance}')
def solve(state):
start = find_pos(state, 'S')
state[start.row][start.col] = 'a'
end = find_pos(state, 'E')
state[end.row][end.col] = 'z'
print(dijkstra(state, start, end))
print(dijkstra(state, end, None))
solve(test_lines)