Advent of Code 2024 - Day 6

# Part 1

 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")))

# Part 2

 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")))