Cleanup, remove unnecessary allocationss, etc.

This commit is contained in:
Daniel Flanagan 2024-12-02 11:43:55 -06:00
parent ab3c6d20bc
commit be69ce7ad8
2 changed files with 41 additions and 42 deletions

View file

@ -16,73 +16,61 @@ impl FromStr for Report {
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
let levels = s let levels = s
.split(" ") .split(" ")
.filter(|s| !s.is_empty())
.map(|s| s.parse()) .map(|s| s.parse())
.collect::<Result<Vec<i64>, ParseIntError>>()?; .collect::<Result<Vec<i64>, ParseIntError>>()?;
Ok(Self { levels }) Ok(Self { levels })
} }
} }
#[derive(PartialEq, Eq)]
enum LevelSafeKind {
Increasing,
Decreasing,
}
impl Report { impl Report {
fn is_safe(&self) -> bool { fn is_safe(&self, skip_index: Option<usize>) -> bool {
Self::is_level_set_safe(&self.levels) let mut ordering: Option<Ordering> = 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 { for i in 0..max {
let mut iter = levels.windows(2); let mut ai = i;
let mut level_safe_kind: Option<LevelSafeKind> = None; let mut bi = ai + 1;
if ai >= skip_index {
while let Some(&[a, b]) = iter.next() { ai += 1
if !Self::safe_level_pair(a, b, &level_safe_kind) { };
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; return false;
} }
if level_safe_kind == None { if ordering == None {
if a > b { ordering = Some(a.cmp(&b))
level_safe_kind = Some(LevelSafeKind::Increasing)
} else {
level_safe_kind = Some(LevelSafeKind::Decreasing)
}
} }
} }
return true; return true;
} }
fn is_safe_with_any_single_level_removed(&self) -> bool { 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() { for i in 0..self.levels.len() {
let levels: Vec<i64> = self if i > 0 {}
.levels if self.is_safe(Some(i)) {
.clone()
.iter()
.enumerate()
.filter(|&(index, _val)| i != index)
.map(|(_index, val)| *val)
.collect();
if Self::is_level_set_safe(&levels) {
return true; return true;
} }
} }
return false; return false;
} }
fn safe_level_pair(a: i64, b: i64, kind: &Option<LevelSafeKind>) -> bool { fn safe_level_pair(a: i64, b: i64, kind: &Option<Ordering>) -> bool {
if a == b { if a == b {
return false; return false;
} }
if (a - b).abs() > 3 { if (a - b).abs() > 3 {
return false; return false;
} }
if a - b < 0 && *kind == Some(LevelSafeKind::Increasing) { if kind.map(|o| o == a.cmp(&b)) == Some(false) {
return false;
}
if a - b > 0 && *kind == Some(LevelSafeKind::Decreasing) {
return false; return false;
} }
return true; return true;
@ -107,7 +95,7 @@ impl FromStr for Data {
impl Data { impl Data {
fn num_safe(&self) -> usize { 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 { fn num_safe_with_dampener(&self) -> usize {
@ -124,7 +112,7 @@ mod tests {
#[test] #[test]
fn 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 1 2 7 8 9
9 7 6 2 1 9 7 6 2 1
1 3 2 4 5 1 3 2 4 5
@ -132,8 +120,18 @@ mod tests {
1 3 6 7 9" 1 3 6 7 9"
.parse() .parse()
.unwrap(); .unwrap();
assert_eq!(report.num_safe(), 2); assert_eq!(data.num_safe(), 2);
assert_eq!(report.num_safe_with_dampener(), 4); 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); // assert_eq!(report.(), 31);
} }
} }

View file

@ -1,5 +1,6 @@
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
pub use std::{ pub use std::{
cmp::Ordering,
collections::HashMap, collections::HashMap,
fs::File, fs::File,
io::Read, io::Read,