use std::str::SplitWhitespace; pub fn run() { let input = include_str!("input"); let safe = input .lines() .map(SplitWhitespaceNumbers::new) .filter_map(|mut line| is_safe(&mut line)) .count(); println!("1. {}", safe); // 510 let safe_corrected = input .lines() .map(ExpandedSplitWhitespaceNumbers::new) .filter_map(|mut line| is_safe_corrected(&mut line)) .count(); println!("2. {}", safe_corrected); // 553 } struct SplitWhitespaceNumbers<'a> { line: SplitWhitespace<'a>, } struct ExpandedSplitWhitespaceNumbers { line: Vec, skip_index: Option, } impl ExpandedSplitWhitespaceNumbers { fn new(line: &str) -> Self { let line = SplitWhitespaceNumbers::new(line).collect(); Self { line, skip_index: None, } } } impl Iterator for ExpandedSplitWhitespaceNumbers { type Item = Vec; fn next(&mut self) -> Option { let mut v = self.line.clone(); if let Some(index) = self.skip_index { if index as usize >= v.len() { return None; } v.remove(index as usize); self.skip_index = Some(index + 1); } else { self.skip_index = Some(0); } Some(v) } } impl<'a> SplitWhitespaceNumbers<'a> { fn new(line: &'a str) -> Self { SplitWhitespaceNumbers { line: line.split_whitespace(), } } } impl<'a> Iterator for SplitWhitespaceNumbers<'a> { type Item = i32; fn next(&mut self) -> Option { let c = self.line.next(); if c.is_none() { return None; } let c = c.unwrap(); let num = c.parse::().unwrap(); Some(num) } } fn is_safe_corrected(numbers: &mut T) -> Option where T: Iterator>, { for variant in numbers.into_iter() { if is_safe(&mut variant.into_iter()).is_some() { return Some(true); } } None } fn is_safe(numbers: &mut T) -> Option where T: Iterator, { let first = numbers.next().unwrap(); let second = numbers.next().unwrap(); let incr = if second - first > 0 { 1 } else { -1 }; let mut cur = second; if !is_safe_interval(first, second, incr) { return None; } loop { let next = numbers.next(); if next.is_none() { break; } let next = next.unwrap(); if !is_safe_interval(cur, next, incr) { return None; } cur = next; } Some(true) } fn is_safe_interval(first: i32, second: i32, incr: i32) -> bool { let diff = second - first; if diff == 0 { return false; } let norm = diff * incr; norm > 0 && norm < 4 }