use advent_of_code::include_aoc; use advent_of_code::{ strings::{convert_to_array, parsenumber}, KD, }; include_aoc!(2024, 02); fn get_numbers(input: &str) -> Vec { input.split(char::is_whitespace).map(parsenumber).collect() } trait SafeCheck { fn safe(&self) -> bool; } #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)] struct Record(Vec); impl SafeCheck for Record { fn safe(&self) -> bool { safe(self.0.clone()) } } #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)] struct DampenedRecord(Vec); impl SafeCheck for DampenedRecord { fn safe(&self) -> bool { for i in 0..self.0.len() { let mut c = self.0.clone(); c.remove(i); if safe(c) { return true; } } false } } fn safe(record: Vec) -> bool { const MAX: u32 = 3; let mut i = record.clone().into_iter(); let mut ups = 0; let mut downs = 0; let mut last = i.next().unwrap(); for level in i { if last < level { last = level; ups += 1 } else if last > level { last = level; downs += 1; } else { ups += 1; downs += 1; } } let direction = if ups > downs { KD::Top } else { KD::Bottom }; let mut errors = 0; i = record.clone().into_iter(); last = i.next().unwrap(); let mut diff: u32; for level in i { diff = last.abs_diff(level); if diff > MAX || diff == 0 { errors += 1; continue; } match (direction, last > level) { (KD::Top, false) | (KD::Bottom, true) => last = level, (KD::Top, true) | (KD::Bottom, false) => errors += 1, _ => unreachable!(), } } if errors > 0 { false } else { true } } fn main() { let numbers = convert_to_array::<_, _, '\n'>(DATA, get_numbers); let mut safe_reports = 0; let mut safe_with_dampener = 0; for report in numbers { if Record(report.clone()).safe() { safe_reports += 1; } if DampenedRecord(report.clone()).safe() { safe_with_dampener += 1; } } println!("Safe Reports: {safe_reports}"); println!("Safe Reports with dampener: {safe_with_dampener}") }