from tools.aoc import AOCDay from tools.tools import compare from typing import Any type Robot = tuple[tuple[int, int], tuple[int, int]] class Day(AOCDay): inputs = [ [ (12, "input14_test"), (225648864, "input14"), ], [ (7847, "input14"), ], ] def parse_input(self) -> list[Robot]: robots = [] for line in self.getInput(): p, v = line.split() px, py = map(int, p[2:].split(",")) vx, vy = map(int, v[2:].split(",")) robots.append(((px, py), (vx, vy))) return robots def move_robots(self, robots: list[Robot], steps: int = 100) -> tuple[tuple[int, int], list[Robot]]: if self.is_test(): dim = (11, 7) else: dim = (101, 103) return dim, [ (((x[0][0] + steps * x[1][0]) % dim[0], (x[0][1] + steps * x[1][1]) % dim[1]), x[1]) for x in robots ] def part1(self) -> Any: q = [[0, 0, 0], [0, 0, 0], [0, 0, 0]] dim, robots = self.move_robots(self.parse_input()) for robot in robots: q[compare(robot[0][1], dim[1] // 2) + 1][compare(robot[0][0], dim[0] // 2) + 1] += 1 return q[0][0] * q[2][0] * q[0][2] * q[2][2] def part2(self) -> Any: robots = self.parse_input() num_robots = len(robots) count = 0 while True: count += 1 _, robots = self.move_robots(robots, steps=1) # We assume, there is only one case where no robots overlap if len(set(x[0] for x in robots)) == num_robots: break return count if __name__ == "__main__": day = Day(2024, 14) day.run(verbose=True)