from tools.aoc import AOCDay from tools.coordinate import Coordinate from tools.grid import Grid from typing import Any def get_reflection_value(grid: Grid, ignore: int = 0) -> int: # search horizontal for x in grid.rangeX(): col = grid.get_column(x) if col == grid.get_column(x + 1): match = True for dx in range(1, grid.maxX - x): if x - dx < 0: break if grid.get_column(x - dx) != grid.get_column(x + dx + 1): match = False break if match and x + 1 != ignore: return x + 1 # search vertical for y in grid.rangeY(): row = grid.get_row(y) if row == grid.get_row(y + 1): match = True for dy in range(1, grid.maxY - y): if y - dy < 0: break if grid.get_row(y - dy) != grid.get_row(y + dy + 1): match = False break if match and 100 * (y + 1) != ignore: return 100 * (y + 1) return -1 class Day(AOCDay): inputs = [ [ (405, "input13_test"), (32035, "input13"), ], [ (400, "input13_test"), (24847, "input13"), ], ] def parse_input(self) -> list[Grid]: return [Grid.from_data(pattern) for pattern in self.getMultiLineInputAsArray()] def part1(self) -> Any: grids = self.parse_input() return sum([get_reflection_value(grid) for grid in grids]) def part2(self) -> Any: grids = self.parse_input() ref_value = 0 for i, grid in enumerate(grids): orig_ref = get_reflection_value(grid) found = False for x in grid.rangeX(): for y in grid.rangeY(): c = Coordinate(x, y) if grid.get(c) == "#": grid.set(c, ".") else: grid.set(c, "#") v = get_reflection_value(grid, orig_ref) if v > 0: ref_value += v found = True break if grid.get(c) == "#": grid.set(c, ".") else: grid.set(c, "#") if found: break return ref_value if __name__ == "__main__": day = Day(2023, 13) day.run(verbose=True)