aoc2023/aoc/day12.py
2023-12-14 01:55:54 +01:00

72 lines
2.2 KiB
Python

from __future__ import annotations
from collections import defaultdict
from dataclasses import dataclass
from typing import TypeAlias
from .aoc import Aoc2, AocParseLines, AocSameImplementation
@dataclass(frozen=True)
class Line:
springs: str
groups: tuple[int, ...]
@classmethod
def from_str(cls, inpt: str, multi: int) -> Line:
springs, groups_str = inpt.split(" ")
springs = "?".join([springs] * multi)
groups = tuple(int(d) for d in groups_str.split(",")) * multi
return Line("." + springs + ".", groups)
P1: TypeAlias = list[Line]
P2: TypeAlias = list[Line]
class Day12(AocSameImplementation[P1], AocParseLines[Line, Line], Aoc2[P1, P2]):
def parseline1(self, inpt: str) -> Line:
return Line.from_str(inpt, 1)
def parseline2(self, inpt: str) -> Line:
return Line.from_str(inpt, 5)
@staticmethod
def fits(line: str, startpos: int, length: int) -> bool:
starter = line[startpos - 1]
segment = line[startpos : startpos + length]
stopper = line[startpos + length]
return "#" not in (starter, stopper) and "." not in segment
def part(self, inpt: P1) -> int:
accum = 0
for line in inpt:
ends = {0: 1}
for i, group in enumerate(line.groups):
next_ends: dict[int, int] = defaultdict(lambda: 0)
for end, amount in ends.items():
for startvalue in range(end + 1, len(line.springs) - group):
if not (
"#" in line.springs[end:startvalue]
or (
i == len(line.groups) - 1
and "#" in line.springs[startvalue + group :]
)
or not Day12.fits(line.springs, startvalue, group)
):
next_ends[startvalue + group] += amount
ends = next_ends
accum += sum(ends.values())
return accum
def main() -> None:
aoc = Day12(2023, 12, example_code_nr1=1, example_code_nr2=1)
aoc.run()
if __name__ == "__main__":
main()