diff --git a/src/bin/day2.rs b/src/bin/day2.rs new file mode 100644 index 0000000..608069f --- /dev/null +++ b/src/bin/day2.rs @@ -0,0 +1,86 @@ +use core::str; +use std::{cmp, time::Instant}; + +use aoc_2024::{load, print_res}; +use bstr::BString; + +pub struct Report(Vec); + +type Parsed = Vec; + +pub fn parsing(input: &BString) -> color_eyre::Result { + str::from_utf8(input)? + .lines() + .map(|l| { + Ok(Report( + l.split_ascii_whitespace() + .map(|x| -> color_eyre::Result { Ok(x.parse()?) }) + .collect::>()?, + )) + }) + .collect() +} + +impl Report { + fn is_safe(&self, mut can_dampen: bool) -> bool { + assert!(self.0.len() >= 2); + + let cmp = self.0[0].cmp(&self.0[1]); + if cmp == cmp::Ordering::Equal { + return false; + } + + for window in self.0.windows(2) { + if cmp != window[0].cmp(&window[1]) { + if can_dampen { + can_dampen = false; + } else { + return false; + } + } + + if window[0].abs_diff(window[1]) > 3 { + if can_dampen { + can_dampen = false; + } else { + return false; + } + } + } + + true + } +} + +pub fn part1(input: Parsed) { + let safe_count = input.iter().filter(|x| x.is_safe(false)).count(); + + print_res!("There are {safe_count} safe reports"); +} + +pub fn part2(input: Parsed) { + let safe_count = input.iter().filter(|x| x.is_safe(true)).count(); + + print_res!("There are {safe_count} safe reports with the dampener"); +} + +pub fn main() -> color_eyre::Result<()> { + let context = load()?; + + let start = Instant::now(); + let parsed = parsing(&context.input)?; + let elapsed = humantime::format_duration(start.elapsed()); + + let start = Instant::now(); + if context.part == 1 { + part1(parsed); + } else { + part2(parsed); + } + let elapsed_part = humantime::format_duration(start.elapsed()); + + println!(" Parsing: {elapsed}"); + println!(" Solving: {elapsed_part}"); + + Ok(()) +}