Cleanup, remove unnecessary allocationss, etc.
This commit is contained in:
parent
ab3c6d20bc
commit
be69ce7ad8
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in a new issue