#[derive(Clone, Copy, Debug)] enum Order { Increasing, Decreasing, } pub fn process_part1(input: &str) -> i32 { let mut safe = 0; input.lines().for_each(|line| { let levels = line .split_whitespace() .map(|e| e.parse::().unwrap()) .collect::>(); if is_safe(levels) { safe += 1; } }); safe } pub fn process_part2(input: &str) -> i32 { let mut safe = 0; input.lines().for_each(|line| { let levels = line .split_whitespace() .map(|e| e.parse::().unwrap()) .collect::>(); if is_safe(levels.clone()) { safe += 1; } else { for idx in 0..levels.len() { let mut new_levels = levels.clone(); new_levels.remove(idx); if is_safe(new_levels) { safe += 1; break; } } } }); safe } fn is_safe(levels: Vec) -> bool { let mut order = None; let mut is_safe = true; for level_pair in levels.windows(2) { let difference = level_pair[0] - level_pair[1]; let new_order = match difference.cmp(&0) { std::cmp::Ordering::Less => Some(Order::Increasing), std::cmp::Ordering::Equal => None, std::cmp::Ordering::Greater => Some(Order::Decreasing), }; let difference = difference.abs(); if difference == 0 { is_safe = false; break; } match (order, new_order) { (None, Some(new_order)) => { if difference <= 3 { order = Some(new_order); } else { is_safe = false; break; } } (Some(Order::Increasing), Some(Order::Decreasing)) | (Some(Order::Decreasing), Some(Order::Increasing)) => { is_safe = false; break; } (None, None) | (Some(_), None) | (Some(Order::Increasing), Some(Order::Increasing)) | (Some(Order::Decreasing), Some(Order::Decreasing)) => { if difference > 3 { is_safe = false; break; } } }; } if is_safe { true //println!("line {line} is safe"); } else { false //println!("line {line} is unsafe"); } } #[cfg(test)] mod tests { use super::*; const INPUT: &str = "7 6 4 2 1 1 2 7 8 9 9 7 6 2 1 1 3 2 4 5 8 6 4 4 1 1 3 6 7 9"; #[test] fn part1() { let result = process_part1(INPUT); assert_eq!(result, 2); } #[test] fn part2() { let result = process_part2(INPUT); assert_eq!(result, 4); } }