use std::{ error::Error, fs::File, io::{BufRead, BufReader}, num::ParseIntError, }; #[derive(PartialEq, Eq)] enum Dir { Ascending, Descending, } impl Dir { fn characterise(a: i16, b: i16) -> Option { let dir = if a < b { Self::Ascending } else { Self::Descending }; if dir.diff_ok(a, b) { Some(dir) } else { None } } fn diff_ok(&self, a: i16, b: i16) -> bool { let diff = match *self { Self::Ascending => b - a, Self::Descending => a - b, }; (1..=3).contains(&diff) } } fn p1cond(report: &[i16]) -> bool { if report.len() <= 1 { return true; } let Some(dir) = Dir::characterise(report[0], report[1]) else { return false; }; for win in report[1..].windows(2) { if !dir.diff_ok(win[0], win[1]) { return false; } } true } fn p2cond(report: &[i16]) -> bool { if report.len() <= 2 { // One element can always be removed to make a safe report return true; } 'outer: for skip_i in 0..report.len() { let it = report .iter() .copied() .enumerate() .filter_map(|(i, e)| if i != skip_i { Some(e) } else { None }); let mut pairs = it.clone().zip(it.skip(1)); let Some((a, b)) = pairs.next() else { continue; }; let Some(dir) = Dir::characterise(a, b) else { continue; }; for (a, b) in pairs { if !dir.diff_ok(a, b) { continue 'outer; } } return true; } false } fn main() -> Result<(), Box> { let f = File::open("input/2")?; let f = BufReader::new(f); let mut input = Vec::new(); for line in f.lines() { let elems = line? .trim_end() .split(' ') .map(str::parse::) .collect::, ParseIntError>>()? .into_boxed_slice(); input.push(elems); } let input = input.into_boxed_slice(); println!("{}", input.iter().filter(|e| p1cond(e)).count()); println!("{}", input.iter().filter(|e| p2cond(e)).count()); Ok(()) }