diff --git a/.aoc_tiles/tiles/2024/14.png b/.aoc_tiles/tiles/2024/14.png new file mode 100644 index 0000000..d5b7fe6 Binary files /dev/null and b/.aoc_tiles/tiles/2024/14.png differ diff --git a/2024/14/example b/2024/14/example new file mode 100644 index 0000000..2455da4 --- /dev/null +++ b/2024/14/example @@ -0,0 +1,12 @@ +p=0,4 v=3,-3 +p=6,3 v=-1,-3 +p=10,3 v=-1,2 +p=2,0 v=2,-1 +p=0,0 v=1,3 +p=3,0 v=-2,-2 +p=7,6 v=-1,-3 +p=3,0 v=-1,-2 +p=9,3 v=2,3 +p=7,3 v=-1,2 +p=2,4 v=2,-3 +p=9,5 v=-3,-3 diff --git a/2024/14/script.py b/2024/14/script.py new file mode 100644 index 0000000..bef439e --- /dev/null +++ b/2024/14/script.py @@ -0,0 +1,84 @@ +from GhostyUtils import aoc +from GhostyUtils.vec2 import Vec2 +from GhostyUtils.grid import Grid +from collections import Counter +import math + + +aoc.argparser.add_argument("-d", "--dimensions", type=str, default="101,103", + help="width,height") +aoc.argparser.add_argument("-s", "--seconds", type=int, default=100) + + +class Rectangle: + def __init__(self, top_left: Vec2, bottom_right: Vec2) -> 'Rectangle': + self.tl = top_left + self.br = bottom_right + + def contains(self, other: Vec2) -> bool: + return ((self.tl.x <= other.x < self.br.x) and + (self.tl.y <= other.y < self.br.y)) + + +class Robot: + def __init__(self, position: Vec2, velocity: Vec2) -> 'Robot': + self.pos = position + self.v = velocity + + def __str__(self) -> str: + return f"p={self.pos.x},{self.pos.y} v={self.v.x},{self.v.y}" + + def step(self, grid: Grid): + self.pos += self.v + self.pos.x %= grid.width() + self.pos.y %= grid.height() + + +def count_quadrants(robots: list[Robot], grid: Grid) -> list[int]: + q_width = grid.width() // 2 + q_height = grid.height() // 2 + quadrants = [ + Rectangle(Vec2(0, 0), Vec2(q_width, q_height)), + Rectangle(Vec2(q_width + 1, 0), Vec2(grid.width(), q_height)), + Rectangle(Vec2(0, q_height + 1), Vec2(q_width, grid.height())), + Rectangle(Vec2(q_width + 1, q_height + 1), Vec2(grid.width(), grid.height())), + ] + + count = [0]*4 + for robot in robots: + for q, quad in enumerate(quadrants): + count[q] += 1 if quad.contains(robot.pos) else 0 + + return count + + +def render_robots(robots: list[Robot], grid: Grid) -> str: + return grid.render_with_overlays([Counter(robot.pos.as_tuple() for robot in robots)]) + + +def main(): + inputs = aoc.read_lines() + + robots = [] + for line in inputs: + robots.append(Robot(*(Vec2.from_str(vec[2:], ',') for vec in line.split()))) + + dimensions = Vec2.from_str(aoc.args.dimensions, ',') + grid = Grid(['.' * dimensions.x] * dimensions.y) + + print("Initial state:") + print(render_robots(robots, grid)) + print() + for s in range(aoc.args.seconds): + for robot in robots: + robot.step(grid) + + print(f"After {s+1} second{'s' if s > 1 else ''}:") + print(render_robots(robots, grid)) + print() + + print(f"p1: {math.prod(count_quadrants(robots, grid))}") + + +if __name__ == "__main__": + main() diff --git a/README.md b/README.md index 26c0322..93409ba 100644 --- a/README.md +++ b/README.md @@ -3,10 +3,10 @@ My solutions to the yearly Advents of Code