use itertools::Itertools; use crate::common::{Answer, Solution}; pub struct Day02; impl Solution for Day02 { fn name(&self) -> &'static str { "Red-Nosed Reports" } fn part_a(&self, input: &str) -> Answer { input .lines() .filter(|l| { let nums = l.split_whitespace().map(|n| n.parse::().unwrap()); is_valid(&nums) }) .count() .into() } fn part_b(&self, input: &str) -> Answer { input .lines() .filter(|l| { let nums = l.split_whitespace().map(|n| n.parse::().unwrap()); let valid = is_valid(&nums); if !valid { let len = nums.clone().count(); for skip_i in 0..len { let new_nums = nums .clone() .enumerate() .filter_map(|(i, n)| (skip_i != i).then_some(n)); if is_valid(&new_nums) { return true; } } } valid }) .count() .into() } } fn is_valid + Clone>(nums: &T) -> bool { let diffs = nums.clone().tuple_windows().map(|(a, b)| a - b); diffs.clone().all(|d| (-3..=-1).contains(&d)) || diffs.clone().all(|d| (1..=3).contains(&d)) } #[cfg(test)] mod test { use super::Day02; use crate::common::Solution; use indoc::indoc; const INPUT: &str = indoc! {" 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 part_a() { assert_eq!(Day02.part_a(INPUT), 2.into()); } #[test] fn part_b() { assert_eq!(Day02.part_b(INPUT), 4.into()); } }