Day 2 complete
This commit is contained in:
@@ -39,6 +39,7 @@ struct LevelTransition {
|
|||||||
state: TransitionState,
|
state: TransitionState,
|
||||||
direction: TransitionDirection,
|
direction: TransitionDirection,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given two level inputs, return a LevelTransition of the state:
|
/// Given two level inputs, return a LevelTransition of the state:
|
||||||
/// - `TransitionState::Bad` if the difference between
|
/// - `TransitionState::Bad` if the difference between
|
||||||
/// the levels is either 0 or great than 3
|
/// the levels is either 0 or great than 3
|
||||||
@@ -67,7 +68,8 @@ fn compare_levels(curr_level: i64, next_level: i64) -> LevelTransition {
|
|||||||
return LevelTransition { state, direction };
|
return LevelTransition { state, direction };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_report_safe_no_dampening(report: Vec<i64>) -> bool {
|
/// Tests if a report is safe
|
||||||
|
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<LevelTransition> = report
|
let report: Vec<LevelTransition> = report
|
||||||
.windows(2)
|
.windows(2)
|
||||||
@@ -99,118 +101,167 @@ fn is_report_safe_no_dampening(report: Vec<i64>) -> bool {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_report_safe_with_dampening(report: Vec<i64>) -> bool {
|
/// Tests if a report is safe or code be made safe if you remove a single
|
||||||
let mut modified_report: Vec<Option<i64>> = vec![None];
|
/// level from the report
|
||||||
let mut tmp_report: Vec<Option<i64>> = report.iter().map(|v| Some(*v)).collect();
|
fn is_report_safe_with_dampening_brute_force(report: &Vec<i64>) -> bool {
|
||||||
modified_report.append(&mut tmp_report);
|
if is_report_safe_no_dampening(&report) {
|
||||||
modified_report.push(None);
|
return true;
|
||||||
|
|
||||||
let mut transitions = Vec::new();
|
|
||||||
for window in modified_report.windows(3) {
|
|
||||||
let window_tuple = (window[0], window[1], window[2]);
|
|
||||||
let state = match window_tuple {
|
|
||||||
// We loop through in 3 value windows. We padded a None on
|
|
||||||
// either side of the vec to detect the ends of the report for special handling.
|
|
||||||
//
|
|
||||||
// If the middle value from the window could be removed to make that section of repo SAFE,
|
|
||||||
//mark as Dempened. We will use this later to determine if there's only a single dampened
|
|
||||||
//value we can remove to meet the dampening criteria.
|
|
||||||
(None, Some(curr), Some(next)) | (Some(curr), Some(next), None) => {
|
|
||||||
// Matched first or last element, which means we only have one check to do
|
|
||||||
// and we always return Dampened instead of Bad
|
|
||||||
let local_transition = compare_levels(curr, next);
|
|
||||||
if local_transition.state == TransitionState::Bad {
|
|
||||||
// shadow bad with dampened since can always
|
|
||||||
// remove the first and last element.
|
|
||||||
LevelTransition {
|
|
||||||
state: TransitionState::DampenedEnd,
|
|
||||||
..local_transition
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
local_transition
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(Some(prev), Some(curr), Some(next)) => {
|
|
||||||
let first_transition = compare_levels(prev, curr);
|
|
||||||
let second_transition = compare_levels(curr, next);
|
|
||||||
if first_transition.state != TransitionState::Good
|
|
||||||
|| second_transition.state != TransitionState::Good
|
|
||||||
|| first_transition.direction != second_transition.direction
|
|
||||||
{
|
|
||||||
let jump_transition = compare_levels(prev, next);
|
|
||||||
if jump_transition.state == TransitionState::Good {
|
|
||||||
//println!("Dampening value window: {:?}", window_tuple);
|
|
||||||
// If we removed the middle value, we would be in a SAFE state, mark as DAMPENED
|
|
||||||
LevelTransition {
|
|
||||||
state: TransitionState::Dampened,
|
|
||||||
..jump_transition
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Removing the middle value does not help us. mark as BAD
|
|
||||||
LevelTransition {
|
|
||||||
state: TransitionState::Bad,
|
|
||||||
..jump_transition
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Both transitions are good and moving in the same directions, so we can return either.
|
|
||||||
second_transition
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => panic!("This should never happen!"),
|
|
||||||
};
|
|
||||||
transitions.push(state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let (mut dampened_cnt, mut prev_direction) = match transitions[0].state {
|
// Loop through removing a single level to test all dampening combinations
|
||||||
TransitionState::Good => (0, transitions[0].direction),
|
for index in 0..report.len() {
|
||||||
TransitionState::Dampened | TransitionState::DampenedEnd => (1, transitions[1].direction),
|
let sub_report = [&report[0..index], &report[index + 1..]].concat();
|
||||||
TransitionState::Bad => {
|
if is_report_safe_no_dampening(&sub_report) {
|
||||||
panic!("This should never happen!");
|
return true;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
for transition in &transitions {
|
|
||||||
match transition.state {
|
|
||||||
TransitionState::Good => {
|
|
||||||
if transition.direction != prev_direction {
|
|
||||||
println!(
|
|
||||||
"Failed for non matching direction: {:?} -> {:?}",
|
|
||||||
report, transitions
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TransitionState::Dampened => {
|
|
||||||
dampened_cnt += 1;
|
|
||||||
if transition.direction != prev_direction {
|
|
||||||
println!(
|
|
||||||
"Failed for non matching direction: {:?} -> {:?}",
|
|
||||||
report, transitions
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TransitionState::DampenedEnd => {
|
|
||||||
dampened_cnt += 1;
|
|
||||||
}
|
|
||||||
TransitionState::Bad => {
|
|
||||||
// If it's marked as bad we can't fix it by dampening, return false
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// We can only dampen one value
|
|
||||||
if dampened_cnt > 1 {
|
|
||||||
println!(
|
|
||||||
"Failed for too much dampening: {:?} -> {:?}",
|
|
||||||
report, transitions
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
prev_direction = transition.direction;
|
|
||||||
}
|
}
|
||||||
true
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fn compare_levels_3(prev_level: i64, curr_level: i64, next_level: i64) -> LevelTransition {
|
||||||
|
// let first_transition = compare_levels(prev_level, curr_level);
|
||||||
|
// let second_transition = compare_levels(curr_level, next_level);
|
||||||
|
// if first_transition.state != TransitionState::Good
|
||||||
|
// || second_transition.state != TransitionState::Good
|
||||||
|
// || first_transition.direction != second_transition.direction
|
||||||
|
// {
|
||||||
|
// let jump_transition = compare_levels(prev_level, next_level);
|
||||||
|
// if jump_transition.state == TransitionState::Good {
|
||||||
|
// //println!("Dampening value window: {:?}", window_tuple);
|
||||||
|
// // If we removed the middle value, we would be in a SAFE state, mark as DAMPENED
|
||||||
|
// LevelTransition {
|
||||||
|
// state: TransitionState::Dampened,
|
||||||
|
// ..jump_transition
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// // Removing the middle value does not help us. mark as BAD
|
||||||
|
// LevelTransition {
|
||||||
|
// state: TransitionState::Bad,
|
||||||
|
// ..jump_transition
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// // Both transitions are good and moving in the same directions, so we can return either.
|
||||||
|
// second_transition
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// fn is_report_safe_with_dampening(report: Vec<i64>) -> bool {
|
||||||
|
// match report.len() {
|
||||||
|
// 0..=2 => return true,
|
||||||
|
// 3 => match compare_levels_3(report[0], report[1], report[2]).state {
|
||||||
|
// TransitionState::Good | TransitionState::Dampened | TransitionState::DampenedEnd => {
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
// TransitionState::Bad => return false,
|
||||||
|
// },
|
||||||
|
// 4.. => {
|
||||||
|
// let first_transition = compare_levels(report[0], report[1]);
|
||||||
|
// let (prev_transition, dampen_cnt) = match first_transition.state {
|
||||||
|
// TransitionState::Bad | TransitionState::Dampened | TransitionState::DampenedEnd => {
|
||||||
|
// // Damnpen first level
|
||||||
|
// let second_transition=compare_levels(report[1], report[2]);
|
||||||
|
// if second_transition.state != TransitionState::Good {
|
||||||
|
// // Already dampened
|
||||||
|
// return false
|
||||||
|
// }
|
||||||
|
// (second_transition, 1)
|
||||||
|
// },
|
||||||
|
// TransitionState::Good => {
|
||||||
|
// let second_transition = compare_levels_3(report[0], report[1], report[2]);
|
||||||
|
// },
|
||||||
|
// }
|
||||||
|
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
|
// fn is_report_safe_with_dampening(report: Vec<i64>) -> bool {
|
||||||
|
// let mut modified_report: Vec<Option<i64>> = vec![None];
|
||||||
|
// let mut tmp_report: Vec<Option<i64>> = report.iter().map(|v| Some(*v)).collect();
|
||||||
|
// modified_report.append(&mut tmp_report);
|
||||||
|
// modified_report.push(None);
|
||||||
|
|
||||||
|
// let mut transitions = Vec::new();
|
||||||
|
// for window in modified_report.windows(3) {
|
||||||
|
// let window_tuple = (window[0], window[1], window[2]);
|
||||||
|
// let state = match window_tuple {
|
||||||
|
// // We loop through in 3 value windows. We padded a None on
|
||||||
|
// // either side of the vec to detect the ends of the report for special handling.
|
||||||
|
// //
|
||||||
|
// // If the middle value from the window could be removed to make that section of repo SAFE,
|
||||||
|
// //mark as Dempened. We will use this later to determine if there's only a single dampened
|
||||||
|
// //value we can remove to meet the dampening criteria.
|
||||||
|
// (None, Some(curr), Some(next)) | (Some(curr), Some(next), None) => {
|
||||||
|
// // Matched first or last element, which means we only have one check to do
|
||||||
|
// // and we always return Dampened instead of Bad
|
||||||
|
// let local_transition = compare_levels(curr, next);
|
||||||
|
// if local_transition.state == TransitionState::Bad {
|
||||||
|
// // shadow bad with dampened since can always
|
||||||
|
// // remove the first and last element.
|
||||||
|
// LevelTransition {
|
||||||
|
// state: TransitionState::DampenedEnd,
|
||||||
|
// ..local_transition
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// local_transition
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// (Some(prev), Some(curr), Some(next)) => compare_levels_3(prev, curr, next),
|
||||||
|
// _ => panic!("This should never happen!"),
|
||||||
|
// };
|
||||||
|
// transitions.push(state);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// let (mut dampened_cnt, mut prev_direction) = match transitions[0].state {
|
||||||
|
// TransitionState::Good => (0, transitions[0].direction),
|
||||||
|
// TransitionState::Dampened | TransitionState::DampenedEnd => (1, transitions[1].direction),
|
||||||
|
// TransitionState::Bad => {
|
||||||
|
// panic!("This should never happen!");
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
// for transition in &transitions {
|
||||||
|
// match transition.state {
|
||||||
|
// TransitionState::Good => {
|
||||||
|
// if transition.direction != prev_direction {
|
||||||
|
// println!(
|
||||||
|
// "Failed for non matching direction: {:?} -> {:?}",
|
||||||
|
// report, transitions
|
||||||
|
// );
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// TransitionState::Dampened => {
|
||||||
|
// dampened_cnt += 1;
|
||||||
|
// if transition.direction != prev_direction {
|
||||||
|
// println!(
|
||||||
|
// "Failed for non matching direction: {:?} -> {:?}",
|
||||||
|
// report, transitions
|
||||||
|
// );
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// TransitionState::DampenedEnd => {
|
||||||
|
// dampened_cnt += 1;
|
||||||
|
// }
|
||||||
|
// TransitionState::Bad => {
|
||||||
|
// // If it's marked as bad we can't fix it by dampening, return false
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// // We can only dampen one value
|
||||||
|
// if dampened_cnt > 1 {
|
||||||
|
// println!(
|
||||||
|
// "Failed for too much dampening: {:?} -> {:?}",
|
||||||
|
// report, transitions
|
||||||
|
// );
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// prev_direction = transition.direction;
|
||||||
|
// }
|
||||||
|
// true
|
||||||
|
// }
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
// Handle command input
|
// Handle command input
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
@@ -230,19 +281,14 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
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_no_dampening(parsed_report.clone()) {
|
if is_report_safe_no_dampening(&parsed_report) {
|
||||||
accumulator_no_dampening += 1;
|
accumulator_no_dampening += 1;
|
||||||
}
|
}
|
||||||
if is_report_safe_with_dampening(parsed_report) {
|
if is_report_safe_with_dampening_brute_force(&parsed_report) {
|
||||||
accumulator_with_dampening += 1;
|
accumulator_with_dampening += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
println!(
|
|
||||||
"test: {}",
|
|
||||||
is_report_safe_with_dampening(vec![1, 3, 2, 4, 5])
|
|
||||||
);
|
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"Number of SAFE reports (No Dampening - Part 1): {}",
|
"Number of SAFE reports (No Dampening - Part 1): {}",
|
||||||
accumulator_no_dampening
|
accumulator_no_dampening
|
||||||
|
|||||||
Reference in New Issue
Block a user