diff --git a/2024/rust/src/day2.rs b/2024/rust/src/day2.rs index 967b25d..3f9de44 100644 --- a/2024/rust/src/day2.rs +++ b/2024/rust/src/day2.rs @@ -16,73 +16,61 @@ impl FromStr for Report { fn from_str(s: &str) -> Result { let levels = s .split(" ") - .filter(|s| !s.is_empty()) .map(|s| s.parse()) .collect::, ParseIntError>>()?; Ok(Self { levels }) } } -#[derive(PartialEq, Eq)] -enum LevelSafeKind { - Increasing, - Decreasing, -} - impl Report { - fn is_safe(&self) -> bool { - Self::is_level_set_safe(&self.levels) - } + fn is_safe(&self, skip_index: Option) -> bool { + let mut ordering: Option = None; + let skip_index = skip_index.unwrap_or(self.levels.len() + 1); + let max = if skip_index < self.levels.len() { + self.levels.len() - 2 + } else { + self.levels.len() - 1 + }; - fn is_level_set_safe(levels: &[i64]) -> bool { - let mut iter = levels.windows(2); - let mut level_safe_kind: Option = None; - - while let Some(&[a, b]) = iter.next() { - if !Self::safe_level_pair(a, b, &level_safe_kind) { + for i in 0..max { + let mut ai = i; + let mut bi = ai + 1; + if ai >= skip_index { + ai += 1 + }; + if bi >= skip_index { + bi += 1 + }; + let (a, b) = (self.levels[ai], self.levels[bi]); + if !Self::safe_level_pair(a, b, &ordering) { return false; } - if level_safe_kind == None { - if a > b { - level_safe_kind = Some(LevelSafeKind::Increasing) - } else { - level_safe_kind = Some(LevelSafeKind::Decreasing) - } + if ordering == None { + ordering = Some(a.cmp(&b)) } } + return true; } fn is_safe_with_any_single_level_removed(&self) -> bool { - // TODO: this allocates for each level combination and so is suboptimal - // best solution I think is to update is_level_set_safe to take index pairs or something and slide those in such a way that we skip one of the indices for i in 0..self.levels.len() { - let levels: Vec = self - .levels - .clone() - .iter() - .enumerate() - .filter(|&(index, _val)| i != index) - .map(|(_index, val)| *val) - .collect(); - if Self::is_level_set_safe(&levels) { + if i > 0 {} + if self.is_safe(Some(i)) { return true; } } return false; } - fn safe_level_pair(a: i64, b: i64, kind: &Option) -> bool { + fn safe_level_pair(a: i64, b: i64, kind: &Option) -> bool { if a == b { return false; } if (a - b).abs() > 3 { return false; } - if a - b < 0 && *kind == Some(LevelSafeKind::Increasing) { - return false; - } - if a - b > 0 && *kind == Some(LevelSafeKind::Decreasing) { + if kind.map(|o| o == a.cmp(&b)) == Some(false) { return false; } return true; @@ -107,7 +95,7 @@ impl FromStr for Data { impl Data { fn num_safe(&self) -> usize { - self.reports.iter().filter(|r| r.is_safe()).count() + self.reports.iter().filter(|r| r.is_safe(None)).count() } fn num_safe_with_dampener(&self) -> usize { @@ -124,7 +112,7 @@ mod tests { #[test] fn test() { - let mut report: Data = "7 6 4 2 1 + let data: Data = "7 6 4 2 1 1 2 7 8 9 9 7 6 2 1 1 3 2 4 5 @@ -132,8 +120,18 @@ mod tests { 1 3 6 7 9" .parse() .unwrap(); - assert_eq!(report.num_safe(), 2); - assert_eq!(report.num_safe_with_dampener(), 4); + assert_eq!(data.num_safe(), 2); + assert_eq!(data.num_safe_with_dampener(), 4); + // assert_eq!(report.(), 31); + } + + #[test] + fn test2() { + let report: Report = Report { + levels: vec![1, 2, 5, 8, 9, 15], + }; + assert_eq!(report.is_safe(None), false); + assert_eq!(report.is_safe_with_any_single_level_removed(), true); // assert_eq!(report.(), 31); } } diff --git a/2024/rust/src/prelude.rs b/2024/rust/src/prelude.rs index 53521ba..098a6b4 100644 --- a/2024/rust/src/prelude.rs +++ b/2024/rust/src/prelude.rs @@ -1,5 +1,6 @@ use std::path::{Path, PathBuf}; pub use std::{ + cmp::Ordering, collections::HashMap, fs::File, io::Read,