#!/usr/bin/env python3 """ Counts how many reports are "safe". A report (one line of space-separated integers) is safe if: 1) Levels are strictly monotonic (all increasing OR all decreasing). 2) Adjacent levels differ by at least 1 and at most 3 (inclusive). Usage: python day2/aoc_2024_day2.py input.txt cat input.txt | python day2/aoc_2024_day2.py """ import argparse class Report: def __init__(self, levels): self.levels = levels @classmethod def from_line(cls, line): parts = line.split() levels = [] for part in parts: levels.append(int(part)) return cls(levels=levels) def is_safe(self): if len(self.levels) < 2: return True # Determine direction (increasing/decreasing) from the first valid step. # 0 => not decided yet # +1 => increasing # -1 => decreasing direction = 0 for i in range(1, len(self.levels)): previous_level = self.levels[i - 1] current_level = self.levels[i] delta = current_level - previous_level # Adjacent levels must change (no equals). if delta == 0: return False # Differ by at least one and at most three. if abs(delta) > 3: return False step_direction = 1 if delta > 0 else -1 if direction == 0: direction = step_direction # The levels are either all increasing or all decreasing. elif step_direction != direction: return False return True def parse_reports(lines): reports = [] for raw in lines: line = raw.strip() if not line: continue reports.append(Report.from_line(line)) return reports def count_safe(reports): safe_count = 0 for report in reports: if report.is_safe(): safe_count += 1 return safe_count def main(): parser = argparse.ArgumentParser("CLI to read sample files.") parser.add_argument("input", help="Input file path (defaults to stdin). Use '-' for stdin.") args = parser.parse_args() reports = parse_reports(args.input) print(count_safe(reports)) return 0 if __name__ == "__main__": main()