// https://adventofcode.com/2024/day/2 // // run command: `cargo run ./input.txt` use std::env; use std::error::Error; use std::fs::File; use std::io::{BufReader, prelude::*}; use std::str::FromStr; /// Parse a report into a Vec fn parse_report(line: &str) -> Result, ::Err> where T: FromStr, { let parsed_line = line .split(char::is_whitespace) .map(|v| v.parse()) .collect::, _>>()?; Ok(parsed_line) } #[derive(Eq, PartialEq)] enum TransitionState { Good, // Good state Bad, // Bad state Dampened, // Could be removed to make a good state } #[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; // If the diff is 0 or greater than 3, return bad state let state = if level_diff == 0 || level_diff.abs() > 3 { TransitionState::Bad } else { TransitionState::Good }; // If great than zero they are ascending let direction = if level_diff > 0 { TransitionDirection::Asc } else { TransitionDirection::Desc }; return LevelTransition { state, direction }; } 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) .map(|l| compare_levels(l[0], l[1])) .collect(); // Setup the loop by checking the first start as a special case let mut prev_transition = &report[0]; if prev_transition.state != TransitionState::Good { return false; } // Check each state for level_transition in report[1..].iter() { // If bad, then it's just bad if level_transition.state != TransitionState::Good { return false; } // If the states aren't the same as the prev, it must // have changed direction if level_transition.direction != prev_transition.direction { return false; } // Setup for next iteration prev_transition = level_transition; } 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 states = Vec::new(); // for window in modified_report.windows(3) { // let window_tuple = (window[0], window[1], window[2]); // let state = match window_tuple { // (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_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 { // } // }, // _ => panic!("This should never happen!"), // } // states.push(state); // } // true // } fn main() -> Result<(), Box> { // Handle command input let args: Vec = env::args().collect(); if args.len() != 2 { panic!( "{} must be run with a single argument of files name!", &args[0] ) } let input_file_string = &args[1]; let input_file = File::open(input_file_string)?; let input_reader = BufReader::new(input_file); let mut accumulator_no_dampening = 0; for line in input_reader.lines() { let line = line?; let parsed_report: Vec = parse_report(&line)?; if is_report_safe_no_dampening(parsed_report) { accumulator_no_dampening += 1; } } println!( "Number of SAFE reports (No Dampening - Part 1): {}", accumulator_no_dampening ); Ok(()) }