split direction (asc/desc) from state (Good/Bad/Dampening)
This commit is contained in:
@@ -21,79 +21,114 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Eq, PartialEq)]
|
#[derive(Eq, PartialEq)]
|
||||||
enum LevelTransitionState {
|
enum TransitionState {
|
||||||
Asc,
|
Good, // Good state
|
||||||
Desc,
|
Bad, // Bad state
|
||||||
Bad,
|
Dampened, // Could be removed to make a good state
|
||||||
Dampened,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compare_levels(curr_level: i64, next_level: i64) -> LevelTransitionState {
|
#[derive(Eq, PartialEq)]
|
||||||
|
enum TransitionDirection {
|
||||||
|
Asc, // level is increasing
|
||||||
|
Desc, // level is decreasing
|
||||||
|
}
|
||||||
|
|
||||||
|
struct LevelTransition {
|
||||||
|
state: TransitionState,
|
||||||
|
direction: TransitionDirection,
|
||||||
|
}
|
||||||
|
/// Given two level inputs, return one of the following:
|
||||||
|
/// - `LevelTransitionState::Bad` if the difference between
|
||||||
|
/// the levels is either 0 or great than 3
|
||||||
|
/// - `LevelTransitionState::Asc` if the value from curr_level to next_level is increasing and it's not BAD
|
||||||
|
/// - `LevelTransitionState::Desc` if the value from curr_level to next_level is decreasing and it's not BAD
|
||||||
|
fn compare_levels(curr_level: i64, next_level: i64) -> LevelTransition {
|
||||||
let level_diff = next_level - curr_level;
|
let level_diff = next_level - curr_level;
|
||||||
|
|
||||||
// If the diff is 0 or greater than 3, return bad stat
|
// If the diff is 0 or greater than 3, return bad state
|
||||||
if level_diff == 0 || level_diff.abs() > 3 {
|
let state = if level_diff == 0 || level_diff.abs() > 3 {
|
||||||
return LevelTransitionState::Bad;
|
TransitionState::Bad
|
||||||
}
|
} else {
|
||||||
|
TransitionState::Good
|
||||||
|
};
|
||||||
|
|
||||||
// If great than zero they are ascending
|
// If great than zero they are ascending
|
||||||
if level_diff > 0 {
|
let direction = if level_diff > 0 {
|
||||||
return LevelTransitionState::Asc;
|
TransitionDirection::Asc
|
||||||
}
|
} else {
|
||||||
//Else we're descending
|
TransitionDirection::Desc
|
||||||
return LevelTransitionState::Desc;
|
};
|
||||||
|
|
||||||
|
return LevelTransition { state, direction };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_report_safe(report: Vec<i64>) -> bool {
|
fn is_report_safe_no_dampening(report: Vec<i64>) -> bool {
|
||||||
// Turn the report into a bunch of states for each adjacent pair in the report
|
// Turn the report into a bunch of states for each adjacent pair in the report
|
||||||
let report: Vec<LevelTransitionState> = report
|
let report: Vec<LevelTransition> = report
|
||||||
.windows(2)
|
.windows(2)
|
||||||
.map(|l| compare_levels(l[0], l[1]))
|
.map(|l| compare_levels(l[0], l[1]))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// Setup the loop by checking the first start as a special case
|
// Setup the loop by checking the first start as a special case
|
||||||
let mut prev_state = &report[0];
|
let mut prev_transition = &report[0];
|
||||||
if prev_state == &LevelTransitionState::Bad {
|
if prev_transition.state != TransitionState::Good {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check each state
|
// Check each state
|
||||||
for level_state in report[1..].iter() {
|
for level_transition in report[1..].iter() {
|
||||||
// If bad, then it's just bad
|
// If bad, then it's just bad
|
||||||
if level_state == &LevelTransitionState::Bad {
|
if level_transition.state != TransitionState::Good {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the states aren't the same as the prev, it must
|
// If the states aren't the same as the prev, it must
|
||||||
// have changed direction
|
// have changed direction
|
||||||
if level_state != prev_state {
|
if level_transition.direction != prev_transition.direction {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup for next iteration
|
// Setup for next iteration
|
||||||
prev_state = level_state;
|
prev_transition = level_transition;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fn is_report_safe_with_dampening(report: Vec<i64>) -> bool {
|
||||||
// let mut modified_report: Vec<Option<i64>> = vec![None];
|
// let mut modified_report: Vec<Option<i64>> = vec![None];
|
||||||
// let mut tmp_report: Vec<Option<i64>> = report.iter().map(|v| Some(*v)).collect();
|
// let mut tmp_report: Vec<Option<i64>> = report.iter().map(|v| Some(*v)).collect();
|
||||||
// modified_report.append(&mut tmp_report);
|
// modified_report.append(&mut tmp_report);
|
||||||
// modified_report.push(None);
|
// modified_report.push(None);
|
||||||
// dbg!(modified_report);
|
|
||||||
|
|
||||||
// let states = Vec::new();
|
// let states = Vec::new();
|
||||||
// for window in modified_report.windows(3) {
|
// for window in modified_report.windows(3) {
|
||||||
// let window_tuple = (window[0], window[1], window[2]);
|
// let window_tuple = (window[0], window[1], window[2]);
|
||||||
// let state = match window_tuple {
|
// let state = match window_tuple {
|
||||||
// (None, Some(curr), Some(next)) => {
|
// (None, Some(curr), Some(next)) | (Some(curr), Some(next), None) => {
|
||||||
// let diff = curr
|
// // Matched first or last element, which means we only have one check to do
|
||||||
|
// // and we always return Dampened instead of Bad
|
||||||
|
// let local_state = compare_levels(curr, next);
|
||||||
|
// if local_state == TransitionState::Bad {
|
||||||
|
// // shadow bad with dampened since can always
|
||||||
|
// // remove the first and last element.
|
||||||
|
// TransitionState::Dampened
|
||||||
|
// } else {
|
||||||
|
// local_state
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// (Some(prev), Some(curr), Some(next)) => {
|
||||||
|
// let first_state = compare_levels(prev, curr);
|
||||||
|
// let second_state = compare_levels(curr, next);
|
||||||
|
// if first_state == TransitionState::Bad || second_state == TransitionState::Bad || first_state != second_state {
|
||||||
|
|
||||||
|
// }
|
||||||
// },
|
// },
|
||||||
// (Some(prev), Some(curr), Some(next)) => (),
|
|
||||||
// (Some(prev), Some(curr), None) => (),
|
|
||||||
// _ => panic!("This should never happen!"),
|
// _ => panic!("This should never happen!"),
|
||||||
// }
|
// }
|
||||||
// states.push(state);
|
// states.push(state);
|
||||||
// }
|
// }
|
||||||
|
// true
|
||||||
|
// }
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
// Handle command input
|
// Handle command input
|
||||||
@@ -109,16 +144,19 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
let input_file = File::open(input_file_string)?;
|
let input_file = File::open(input_file_string)?;
|
||||||
let input_reader = BufReader::new(input_file);
|
let input_reader = BufReader::new(input_file);
|
||||||
|
|
||||||
let mut accumulator = 0;
|
let mut accumulator_no_dampening = 0;
|
||||||
for line in input_reader.lines() {
|
for line in input_reader.lines() {
|
||||||
let line = line?;
|
let line = line?;
|
||||||
let parsed_report: Vec<i64> = parse_report(&line)?;
|
let parsed_report: Vec<i64> = parse_report(&line)?;
|
||||||
if is_report_safe(parsed_report) {
|
if is_report_safe_no_dampening(parsed_report) {
|
||||||
accumulator += 1;
|
accumulator_no_dampening += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("Number of SAFE reports: {}", accumulator);
|
println!(
|
||||||
|
"Number of SAFE reports (No Dampening - Part 1): {}",
|
||||||
|
accumulator_no_dampening
|
||||||
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user