Advent of Code 2024 - Day 14

# Part 1

 1from __future__ import annotations
 2
 3import typing
 4import dataclasses
 5import re
 6import collections
 7
 8@dataclasses.dataclass
 9class Vector:
10    x: int
11    y: int
12
13    def __add__(self, b: typing.Self):
14        return Vector(self.x + b.x, self.y + b.y)
15
16@dataclasses.dataclass
17class Guard:
18    pos: Vector
19    vel: Vector
20
21    def move(self, shape: Vector):
22        self.pos.x = (self.pos.x + self.vel.x) % shape.x
23        self.pos.y = (self.pos.y + self.vel.y) % shape.y
24
25
26    def get_quadrant(self, shape: Vector):
27        if self.pos.x < shape.x // 2:
28            x = 0
29        elif shape.x - shape.x // 2 <= self.pos.x:
30            x = 1
31        else:
32            return None
33
34        if self.pos.y < shape.y // 2:
35            y = 0
36        elif shape.y - shape.y // 2 <= self.pos.y:
37            y = 1
38        else:
39            return None
40
41        return (x, y)
42
43def get_data(path):
44    with open(path) as f:
45        data = f.read()
46
47    for guard_line in data.strip().splitlines():
48        if m := re.search(r"p=(-?\d+),(-?\d+) v=(-?\d+),(-?\d+)", guard_line):
49            pos = Vector(int(m.group(1)), int(m.group(2)))
50            vel = Vector(int(m.group(3)), int(m.group(4)))
51            yield Guard(pos, vel)
52        else:
53            raise Exception("Could not parse line `{line}`")
54
55
56def main(guards: list[Guard], shape: Vector, iterations=100):
57    for _ in range(iterations):
58        for guard in guards:
59            guard.move(shape)
60
61    counter = collections.Counter(g.get_quadrant(shape) for g in guards)
62    total = 1
63    for k, v in counter.items():
64        if k is not None:
65            total *= v
66    return total
67
68if __name__ == "__main__":
69    # print(main(list(get_data("day_14_input_test.txt")), Vector(11, 7)))
70    print(main(list(get_data("day_14_input.txt")), Vector(101, 103)))

# Part 2

 1from __future__ import annotations
 2
 3import typing
 4import dataclasses
 5import re
 6import collections
 7
 8@dataclasses.dataclass
 9class Vector:
10    x: int
11    y: int
12
13    def __add__(self, b: typing.Self):
14        return Vector(self.x + b.x, self.y + b.y)
15
16@dataclasses.dataclass
17class Guard:
18    pos: Vector
19    vel: Vector
20
21    def move(self, shape: Vector):
22        self.pos.x = (self.pos.x + self.vel.x) % shape.x
23        self.pos.y = (self.pos.y + self.vel.y) % shape.y
24
25
26    def get_quadrant(self, shape: Vector):
27        if self.pos.x < shape.x // 2:
28            x = 0
29        elif shape.x - shape.x // 2 <= self.pos.x:
30            x = 1
31        else:
32            return None
33
34        if self.pos.y < shape.y // 2:
35            y = 0
36        elif shape.y - shape.y // 2 <= self.pos.y:
37            y = 1
38        else:
39            return None
40
41        return (x, y)
42
43def get_data(path):
44    with open(path) as f:
45        data = f.read()
46
47    for guard_line in data.strip().splitlines():
48        if m := re.search(r"p=(-?\d+),(-?\d+) v=(-?\d+),(-?\d+)", guard_line):
49            pos = Vector(int(m.group(1)), int(m.group(2)))
50            vel = Vector(int(m.group(3)), int(m.group(4)))
51            yield Guard(pos, vel)
52        else:
53            raise Exception("Could not parse line `{line}`")
54
55
56def format_grid(guards, shape):
57    grid = [["." for _ in range(shape.x)] for _ in range(shape.y)]
58    for g in guards:
59        grid[g.pos.y][g.pos.x] = "x"
60
61    return "\n".join("".join(row) for row in grid)
62
63def main(guards: list[Guard], shape: Vector, iterations=10000):
64    for i in range(iterations):
65        for guard in guards:
66            guard.move(shape)
67        grid_str = format_grid(guards, shape)
68        if "x" * 10 in grid_str:
69            print(i + 1)
70            print(grid_str)
71
72if __name__ == "__main__":
73    # print(main(list(get_data("day_14_input_test.txt")), Vector(11, 7)))
74    print(main(list(get_data("day_14_input.txt")), Vector(101, 103)))