Files

89 lines
2.3 KiB
Python

from dataclasses import dataclass
from functools import cached_property
from itertools import pairwise
from textwrap import dedent
from typing import Iterator, override
from unittest import TestCase
from more_itertools import ilen
from puzzles._solver import Solver
@dataclass
class Report:
levels: tuple[int, ...]
@cached_property
def deltas(self) -> tuple[int, ...]:
return tuple(b - a for a, b in pairwise(self.levels))
def is_gradual_monotonic(self) -> bool:
sign = 1 if self.deltas[0] > 0 else -1
return all(
delta != 0 and delta / abs(delta) == sign and abs(delta) < 4
for delta in self.deltas
)
def permute_dampened_variations(self) -> Iterator["Report"]:
return (
Report(self.levels[:i] + self.levels[i + 1 :])
for i in range(0, len(self.levels) + 1)
)
class DayTwoSolver(Solver):
reports: list[Report]
@override
def __init__(self, puzzle_input: str):
self.reports = list(
Report(tuple(int(level) for level in line.split(" ")))
for line in puzzle_input.strip().splitlines()
)
@override
def solve_p1(self) -> int:
safe_reports = filter(Report.is_gradual_monotonic, self.reports)
return ilen(safe_reports)
@override
def solve_p2(self) -> int:
safe_reports = filter(
lambda report: any(
report_variation.is_gradual_monotonic()
for report_variation in report.permute_dampened_variations()
),
self.reports,
)
return ilen(safe_reports)
class TestDayNSolver(TestCase):
def test(self):
solver = DayTwoSolver(
dedent(
"""
7 6 4 2 1
1 2 7 8 9
9 7 6 2 1
1 3 2 4 5
8 6 4 4 1
1 3 6 7 9
"""
)
)
self.assertListEqual(
solver.reports,
[
Report((7, 6, 4, 2, 1)),
Report((1, 2, 7, 8, 9)),
Report((9, 7, 6, 2, 1)),
Report((1, 3, 2, 4, 5)),
Report((8, 6, 4, 4, 1)),
Report((1, 3, 6, 7, 9)),
],
)
self.assertEqual(solver.solve_p1(), 2)
self.assertEqual(solver.solve_p2(), 4)