64 lines
1.8 KiB
Python
64 lines
1.8 KiB
Python
from itertools import islice
|
|
from typing import Iterator
|
|
|
|
from more_itertools import ilen
|
|
|
|
test_input = """
|
|
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
|
|
""".strip()
|
|
|
|
test_solution_p1 = 2
|
|
test_solution_p2 = 4
|
|
|
|
|
|
def solve_p1(puzzle_input: str) -> int:
|
|
reports = _parse_reports(puzzle_input)
|
|
delta_reports = (_deltas(report) for report in reports)
|
|
safe_delta_reports = filter(_is_gradual_monotonic, delta_reports)
|
|
return ilen(safe_delta_reports)
|
|
|
|
|
|
def solve_p2(puzzle_input: str) -> int:
|
|
reports = _parse_reports(puzzle_input)
|
|
dampened_report_collections = (_dampen_permutations(report) for report in reports)
|
|
delta_report_collections = (
|
|
(_deltas(report) for report in report_collection)
|
|
for report_collection in dampened_report_collections
|
|
)
|
|
safe_report_collections = filter(
|
|
lambda delta_report_collection: any(
|
|
_is_gradual_monotonic(delta_report)
|
|
for delta_report in delta_report_collection
|
|
),
|
|
delta_report_collections,
|
|
)
|
|
return ilen(safe_report_collections)
|
|
|
|
|
|
def _parse_reports(puzzle_input: str) -> Iterator[tuple[int, ...]]:
|
|
lines = puzzle_input.splitlines()
|
|
return (tuple(int(level) for level in line.split(" ")) for line in lines)
|
|
|
|
|
|
def _deltas(report: tuple[int, ...]) -> tuple[int, ...]:
|
|
pairs = zip(report, islice(report, 1, None))
|
|
return tuple(b - a for a, b in pairs)
|
|
|
|
|
|
def _is_gradual_monotonic(delta_report: tuple[int]) -> bool:
|
|
sign = 1 if delta_report[0] > 0 else -1
|
|
return all(
|
|
delta != 0 and delta / abs(delta) == sign and abs(delta) < 4
|
|
for delta in delta_report
|
|
)
|
|
|
|
|
|
def _dampen_permutations(report: tuple[int, ...]) -> Iterator[tuple[int, ...]]:
|
|
yield report
|
|
yield from (report[:i] + report[i + 1 :] for i in range(0, len(report)))
|