-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathp20.py
103 lines (87 loc) · 2.82 KB
/
p20.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
from typing import Any
WALL = "#"
START = "S"
END = "E"
EMPTY = "."
DIRECTIONS = [(1, 0), (0, 1), (-1, 0), (0, -1)]
def load_input():
with open("p20.input.txt", "r") as f:
return Grid(f)
class Grid:
def __init__(self, f):
self.grid = []
self.start = None
self.end = None
for y, line in enumerate(f.readlines()):
line = line.strip()
gridline = []
for x, c in enumerate(line):
if c == START:
self.start = (x, y)
if c == END:
self.end = (x, y)
gridline.append(c)
self.grid.append(gridline)
def in_grid(self, x: int, y: int):
return 0 <= y < len(self.grid) and 0 <= x < len(self.grid[y])
def at(self, x: int, y: int) -> Any:
if self.in_grid(x, y):
return self.grid[y][x]
return None
def set(self, x: int, y: int, val: Any) -> None:
if self.in_grid(x, y):
self.grid[y][x] = val
def moves_from(self, x: int, y: int) -> (int, int):
for d in DIRECTIONS:
dx, dy = d
nx, ny = dx + x, dy + y
if self.in_grid(nx, ny):
yield nx, ny
def points_distance_from(self, x: int, y: int, dist: int):
points = set()
for dx in range(0, dist + 1):
dy = dist - dx
for mult in [(1, 1), (-1, 1), (1, -1), (-1, -1)]:
mx, my = mult
px, py = x + (mx * dx), y + (my * dy)
if self.in_grid(px, py) and (px, py) not in points:
yield px, py
points.add((px, py))
def set_distances(grid: Grid) -> [(int, int)]:
xy = grid.start
distance = 0
path = []
while xy != grid.end:
path.append(xy)
grid.set(*xy, distance)
distance += 1
for move in grid.moves_from(*xy):
at_move = grid.at(*move)
if at_move in (EMPTY, END):
xy = move
break
path.append(xy)
grid.set(*xy, distance)
return path
if __name__ == "__main__":
grid = load_input()
path = set_distances(grid)
save_100s_2 = 0
save_100s_20 = 0
for locxy in path:
start_cost = grid.at(*locxy)
for dist in range(2, 21):
for px, py in grid.points_distance_from(*locxy, dist):
assert isinstance(start_cost, int)
end_cost = grid.at(px, py)
if not isinstance(end_cost, int):
continue
diff = end_cost - start_cost - dist
if diff <= 0:
continue
if diff >= 100:
save_100s_20 += 1
if dist == 2:
save_100s_2 += 1
print(save_100s_2)
print(save_100s_20)