02.rs
1 #![feature(test)] 2 3 use itertools::Itertools; 4 5 type Input = Vec<Vec<i32>>; 6 7 fn setup(input: &str) -> Input { 8 input 9 .lines() 10 .map(|line| { 11 line.split_whitespace() 12 .map(|x| x.parse().unwrap()) 13 .collect() 14 }) 15 .collect() 16 } 17 18 #[derive(Debug, Clone, Copy, Default)] 19 struct DiffCounts { 20 positive: usize, 21 negative: usize, 22 invalid: usize, 23 } 24 25 impl DiffCounts { 26 fn from_nums(nums: &[i32]) -> Self { 27 nums.iter() 28 .tuple_windows() 29 .fold(Self::default(), |c, (a, b)| c.add(b - a)) 30 } 31 32 fn classify(diff: i32) -> Self { 33 Self { 34 positive: (1..=3).contains(&diff) as _, 35 negative: (-3..=-1).contains(&diff) as _, 36 invalid: (diff == 0 || diff.abs() > 3) as _, 37 } 38 } 39 40 fn add(self, diff: i32) -> Self { 41 let other = Self::classify(diff); 42 Self { 43 positive: self.positive + other.positive, 44 negative: self.negative + other.negative, 45 invalid: self.invalid + other.invalid, 46 } 47 } 48 49 fn sub(self, diff: i32) -> Self { 50 let other = Self::classify(diff); 51 Self { 52 positive: self.positive - other.positive, 53 negative: self.negative - other.negative, 54 invalid: self.invalid - other.invalid, 55 } 56 } 57 58 fn check(self) -> bool { 59 self.invalid == 0 && (self.positive == 0 || self.negative == 0) 60 } 61 } 62 63 fn part1(input: &Input) -> usize { 64 input 65 .iter() 66 .filter(|nums| DiffCounts::from_nums(nums).check()) 67 .count() 68 } 69 70 fn check_with_tolerance(nums: &[i32]) -> bool { 71 let counts = nums 72 .iter() 73 .tuple_windows() 74 .fold(DiffCounts::default(), |c, (a, b)| c.add(b - a)); 75 76 if counts.check() 77 || counts.sub(nums[1] - nums[0]).check() 78 || counts 79 .sub(nums[nums.len() - 1] - nums[nums.len() - 2]) 80 .check() 81 { 82 return true; 83 } 84 85 nums.iter() 86 .tuple_windows() 87 .any(|(a, b, c)| counts.sub(b - a).sub(c - b).add(c - a).check()) 88 } 89 90 fn part2(input: &Input) -> usize { 91 input 92 .iter() 93 .filter(|nums| check_with_tolerance(nums)) 94 .count() 95 } 96 97 aoc::main!(2024, 2, ex: 1); 98 99 #[cfg(test)] 100 mod tests { 101 use super::*; 102 103 #[test] 104 fn wolflu() { 105 assert!(check_with_tolerance(&[18, 21, 23, 22, 23, 26, 28])); 106 } 107 }