from tools.aoc import AOCDay from typing import Any from tools.coordinate import Coordinate from tools.grid import Grid class Day(AOCDay): inputs = [ [ (4361, "input3_test"), (533775, "input3_dennis"), (560670, "input3"), ], [ (467835, "input3_test"), (78236071, "input3_dennis"), (91622824, "input3"), ], ] def parse_input(self) -> Grid: grid = Grid() num_found = 0 number_digits = set() number = 0 for y, l in enumerate(self.getInput()): for x, c in enumerate(l): if c.isdigit(): number_digits.add((x, y)) number = number * 10 + int(c) else: if number_digits: for nc in number_digits: grid.set(Coordinate(*nc), (num_found, number)) num_found += 1 number_digits = set() number = 0 if c != ".": grid.set(Coordinate(x, y), c) return grid def part1(self) -> Any: grid = self.parse_input() part_number_sum = 0 seen = set() for c in grid.getActiveCells(): v = grid.get(c) if not isinstance(v, tuple): continue num_id, num_value = v if num_id in seen: continue for n in grid.getNeighboursOf(c, includeDefault=False, includeDiagonal=True): nv = grid.get(n) if nv and not isinstance(nv, tuple): part_number_sum += num_value seen.add(num_id) break return part_number_sum def part2(self) -> Any: grid = self.parse_input() gear_ratio_sum = 0 for c in grid.getActiveCells(): if grid.get(c) != "*": continue count = 0 ratio = 1 seen = set() for n in grid.getNeighboursOf(c, includeDiagonal=True, includeDefault=False): num = grid.get(n) if num and isinstance(num, tuple) and num[0] not in seen: ratio *= num[1] count += 1 seen.add(num[0]) if count == 2: gear_ratio_sum += ratio return gear_ratio_sum if __name__ == "__main__": day = Day(2023, 3) day.run(verbose=True)