70 lines
2.1 KiB
Python
70 lines
2.1 KiB
Python
from typing import Callable, Iterator
|
|
import sys
|
|
|
|
|
|
def check_report_basic(levels: tuple[int, ...]) -> bool:
|
|
safe = True
|
|
differences = [next_level - level for level, next_level in zip(levels, levels[1:])]
|
|
safe = safe and (
|
|
all(-3 <= diff <= -1 for diff in differences)
|
|
or all(1 <= diff <= 3 for diff in differences)
|
|
)
|
|
return safe
|
|
|
|
def check_report_damp(levels: tuple[int, ...]) -> bool:
|
|
# Obvious solution is using check_report_basic iteratively..
|
|
# Is there a better solution?
|
|
safe = check_report_basic(levels)
|
|
safe = safe or any(check_report_basic(levels[:i] + levels[i+1:]) for i in range(len(levels)))
|
|
return safe
|
|
|
|
def tester(data: dict[tuple[int, ...], bool], checker: Callable[[tuple[int, ...]], bool]):
|
|
for report, expected in data.items():
|
|
assert (checker(report) is expected), f"Check failed: {report=} should be {expected=}"
|
|
|
|
def tests():
|
|
print("Testing basic check")
|
|
data = {
|
|
(7, 6, 4, 2, 1): True,
|
|
(1, 2, 7, 8, 9): False,
|
|
(9, 7, 6, 2, 1): False,
|
|
(1, 3, 2, 4, 5): False,
|
|
(8, 6, 4, 4, 1): False,
|
|
(1, 3, 6, 7, 9): True,
|
|
}
|
|
tester(data, check_report_basic)
|
|
print("Basic check passed.")
|
|
|
|
print("Testing dampened check.")
|
|
data = {
|
|
(7, 6, 4, 2, 1): True,
|
|
(1, 2, 7, 8, 9): False,
|
|
(9, 7, 6, 2, 1): False,
|
|
(1, 3, 2, 4, 5): True,
|
|
(8, 6, 4, 4, 1): True,
|
|
(1, 3, 6, 7, 9): True,
|
|
}
|
|
tester(data, check_report_damp)
|
|
print("Damp check passed.")
|
|
|
|
def main():
|
|
tests()
|
|
filename = sys.argv[1]
|
|
reports = load_data(filename)
|
|
total = sum(map(check_report_basic, reports))
|
|
print(f"Total safe reports without damping: {total}")
|
|
|
|
reports = load_data(filename)
|
|
total = sum(map(check_report_damp, reports))
|
|
print(f"Total safe reports with damping: {total}")
|
|
|
|
|
|
def load_data(filename) -> Iterator[tuple[int, ...]]:
|
|
with open(filename) as f:
|
|
for line in f:
|
|
if line.strip():
|
|
yield tuple(map(int, line.split()))
|
|
|
|
if __name__ == '__main__':
|
|
main()
|