1import dataclasses
2
3
4@dataclasses.dataclass
5class Vector:
6 y: int
7 x: int
8
9
10ROTATE = [
11 Vector(-1, 0),
12 Vector(0, 1),
13 Vector(1, 0),
14 Vector(0, -1),
15]
16
17
18def get_data(path):
19 with open(path) as f:
20 return [list(row) for row in f.read().strip().split()]
21
22
23def main(grid) -> int:
24 #
25 # Find the dude's starting position
26 #
27 pos = Vector(0, 0)
28 for y, row in enumerate(grid):
29 for x, c in enumerate(row):
30 if c == "^":
31 pos = Vector(y, x)
32
33 #
34 # Have the starting tile be considered marked
35 #
36 checked_tiles = 1
37 grid[pos.y][pos.x] = "X"
38
39 #
40 # Have the dude walk
41 #
42 direction = Vector(-1, 0)
43 while True:
44 next_pos = Vector(pos.y + direction.y, pos.x + direction.x)
45 if not (next_pos.x >= 0 and next_pos.y >= 0 and next_pos.x < len(grid[0]) and next_pos.y < len(grid)):
46 break
47 next_tile = grid[next_pos.y][next_pos.x]
48
49 if next_tile == "#":
50 direction = ROTATE[(ROTATE.index(direction) + 1) % len(ROTATE)]
51 continue
52 elif next_tile == ".":
53 grid[next_pos.y][next_pos.x] = "X"
54 checked_tiles += 1
55 pos = next_pos
56
57 for row in grid:
58 print("".join(row))
59 return checked_tiles
60
61
62
63if __name__ == '__main__':
64 print(main(get_data("day_6_input.txt")))
1import dataclasses
2import copy
3
4@dataclasses.dataclass(frozen=True)
5class Vector:
6 y: int
7 x: int
8
9ROTATE = [
10 Vector(-1, 0),
11 Vector(0, 1),
12 Vector(1, 0),
13 Vector(0, -1),
14]
15
16
17def get_data(path):
18 with open(path) as f:
19 return [list(row) for row in f.read().strip().split()]
20
21
22def is_loop(grid) -> bool:
23 #
24 # Find the dude's starting position
25 #
26 pos = Vector(0, 0)
27 for y, row in enumerate(grid):
28 for x, c in enumerate(row):
29 if c == "^":
30 pos = Vector(y, x)
31
32
33 #
34 # Have the dude walk
35 #
36 visited = set()
37 direction = Vector(-1, 0)
38 grid[pos.y][pos.x] = "."
39
40 while True:
41 #
42 # If the guard has walked here before then quit
43 #
44 if (pos, direction) in visited:
45 return True
46 visited.add((pos, direction))
47
48 #
49 # If we'd walk off the edge then we ain't looping
50 #
51 next_pos = Vector(pos.y + direction.y, pos.x + direction.x)
52 if not (next_pos.x >= 0 and next_pos.y >= 0 and next_pos.x < len(grid[0]) and next_pos.y < len(grid)):
53 return False
54
55 #
56 # Decide what to do next by looking at the next tile
57 #
58 next_tile = grid[next_pos.y][next_pos.x]
59 if next_tile == "#":
60 direction = ROTATE[(ROTATE.index(direction) + 1) % len(ROTATE)]
61 else:
62 pos = next_pos
63
64
65def main(grid):
66 output = 0
67 #
68 # Place an obstacle at every single grid position and check if it
69 # leads to a looping guard
70 #
71 for y in range(len(grid)):
72 for x in range(len(grid[0])):
73 if grid[y][x] == "#":
74 continue
75 new_grid = copy.deepcopy(grid)
76 new_grid[y][x] = "#"
77 output += int(is_loop(new_grid))
78 return output
79
80
81if __name__ == '__main__':
82 print(main(get_data("day_6_input_test_2.txt")))