From 75ea19302ae7265a1d0360cd8ac9a3cc864d300d Mon Sep 17 00:00:00 2001 From: Bearmine Date: Mon, 26 May 2025 08:06:54 -0500 Subject: [PATCH] Day 2 complete --- day_02/src/main.rs | 274 ++++++++++++++++++++++++++------------------- 1 file changed, 160 insertions(+), 114 deletions(-) diff --git a/day_02/src/main.rs b/day_02/src/main.rs index 3686beb..20fdb0a 100644 --- a/day_02/src/main.rs +++ b/day_02/src/main.rs @@ -39,6 +39,7 @@ struct LevelTransition { state: TransitionState, direction: TransitionDirection, } + /// Given two level inputs, return a LevelTransition of the state: /// - `TransitionState::Bad` if the difference between /// 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 }; } -fn is_report_safe_no_dampening(report: Vec) -> bool { +/// Tests if a report is safe +fn is_report_safe_no_dampening(report: &Vec) -> bool { // Turn the report into a bunch of states for each adjacent pair in the report let report: Vec = report .windows(2) @@ -99,118 +101,167 @@ fn is_report_safe_no_dampening(report: Vec) -> bool { return true; } -fn is_report_safe_with_dampening(report: Vec) -> bool { - let mut modified_report: Vec> = vec![None]; - let mut tmp_report: Vec> = 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)) => { - 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); +/// Tests if a report is safe or code be made safe if you remove a single +/// level from the report +fn is_report_safe_with_dampening_brute_force(report: &Vec) -> bool { + if is_report_safe_no_dampening(&report) { + return true; } - 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!"); + // Loop through removing a single level to test all dampening combinations + for index in 0..report.len() { + let sub_report = [&report[0..index], &report[index + 1..]].concat(); + if is_report_safe_no_dampening(&sub_report) { + 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) -> 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) -> bool { +// let mut modified_report: Vec> = vec![None]; +// let mut tmp_report: Vec> = 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> { // Handle command input let args: Vec = env::args().collect(); @@ -230,19 +281,14 @@ fn main() -> Result<(), Box> { for line in input_reader.lines() { let line = line?; let parsed_report: Vec = parse_report(&line)?; - if is_report_safe_no_dampening(parsed_report.clone()) { + if is_report_safe_no_dampening(&parsed_report) { 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; } } - println!( - "test: {}", - is_report_safe_with_dampening(vec![1, 3, 2, 4, 5]) - ); - println!( "Number of SAFE reports (No Dampening - Part 1): {}", accumulator_no_dampening