aoc2023/aoc/day13.py

90 lines
2.2 KiB
Python

from __future__ import annotations
from array import array
from typing import TypeAlias
from itertools import groupby, islice
from .aoc import Aoc2, AocSameParser
from .day11 import Matrix
P1: TypeAlias = list[Matrix]
class Day13(AocSameParser[P1], Aoc2[P1, P1]):
def parseinput(self, inpt: str) -> P1:
fields = inpt.split("\n\n")
return [Matrix(group) for group in fields]
@staticmethod
def check_horiz(m: Matrix, max_diffs: int) -> int | None:
rows = list(m.iter_rows())
nr_rows = len(rows)
for x in range(1, nr_rows):
y = 0
if x > nr_rows / 2:
y = x + x - nr_rows
diff = Day13.diff_lines(rows[y:x], list(reversed(rows[x : x + x - y])))
if diff == max_diffs:
return x
return None
@staticmethod
def check_vert(m: Matrix, max_diffs: int) -> int | None:
cols = list(m.iter_cols())
nr_cols = len(cols)
for x in range(1, nr_cols):
y = 0
if x > nr_cols / 2:
y = x + x - nr_cols
diff = Day13.diff_lines(cols[y:x], list(reversed(cols[x : x + x - y])))
if diff == max_diffs:
return x
return None
@staticmethod
def diff_lines(a: list[array[str]], b: list[array[str]]) -> int:
return sum(map(lambda x, y: Day13.diff_line(x, y), a, b))
@staticmethod
def diff_line(a: array[str], b: array[str]) -> int:
return sum(map(lambda x, y: x != y, a, b))
@staticmethod
def compute(inpt: P1, max_diffs: int) -> int:
verts = 0
horiz = 0
for m in inpt:
mverts = Day13.check_vert(m, max_diffs)
if mverts is not None:
verts += mverts
else:
mhoriz = Day13.check_horiz(m, max_diffs)
if mhoriz is not None:
horiz += mhoriz
return verts + 100 * horiz
def part1(self, inpt: P1) -> int:
return self.compute(inpt, 0)
def part2(self, inpt: P1) -> int:
return self.compute(inpt, 1)
def main() -> None:
aoc = Day13(2023, 13, example_code_nr2=0)
aoc.run()
if __name__ == "__main__":
main()