2025-05-25 17:15:31 -05:00
|
|
|
// https://adventofcode.com/2024/day/2
|
|
|
|
|
//
|
|
|
|
|
// run command: `cargo run ./input.txt`
|
|
|
|
|
|
2025-05-25 16:02:23 -05:00
|
|
|
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<T>
|
|
|
|
|
fn parse_report<T>(line: &str) -> Result<Vec<T>, <T as FromStr>::Err>
|
|
|
|
|
where
|
|
|
|
|
T: FromStr,
|
|
|
|
|
{
|
|
|
|
|
let parsed_line = line
|
|
|
|
|
.split(char::is_whitespace)
|
|
|
|
|
.map(|v| v.parse())
|
|
|
|
|
.collect::<Result<Vec<T>, _>>()?;
|
|
|
|
|
Ok(parsed_line)
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-25 17:15:31 -05:00
|
|
|
#[derive(Eq, PartialEq)]
|
|
|
|
|
enum LevelTransitionState {
|
2025-05-25 16:02:23 -05:00
|
|
|
Asc,
|
|
|
|
|
Desc,
|
2025-05-25 17:15:31 -05:00
|
|
|
Bad,
|
|
|
|
|
Dampened,
|
2025-05-25 16:02:23 -05:00
|
|
|
}
|
|
|
|
|
|
2025-05-25 17:15:31 -05:00
|
|
|
fn compare_levels(curr_level: i64, next_level: i64) -> LevelTransitionState {
|
|
|
|
|
let level_diff = next_level - curr_level;
|
|
|
|
|
|
|
|
|
|
// If the diff is 0 or greater than 3, return bad stat
|
|
|
|
|
if level_diff == 0 || level_diff.abs() > 3 {
|
|
|
|
|
return LevelTransitionState::Bad;
|
|
|
|
|
}
|
|
|
|
|
// If great than zero they are ascending
|
|
|
|
|
if level_diff > 0 {
|
|
|
|
|
return LevelTransitionState::Asc;
|
|
|
|
|
}
|
|
|
|
|
//Else we're descending
|
|
|
|
|
return LevelTransitionState::Desc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn is_report_safe(report: Vec<i64>) -> bool {
|
|
|
|
|
// Turn the report into a bunch of states for each adjacent pair in the report
|
|
|
|
|
let report: Vec<LevelTransitionState> = 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_state = &report[0];
|
|
|
|
|
if prev_state == &LevelTransitionState::Bad {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check each state
|
|
|
|
|
for level_state in report[1..].iter() {
|
|
|
|
|
// If bad, then it's just bad
|
|
|
|
|
if level_state == &LevelTransitionState::Bad {
|
|
|
|
|
return false;
|
2025-05-25 16:02:23 -05:00
|
|
|
}
|
2025-05-25 17:15:31 -05:00
|
|
|
|
|
|
|
|
// If the states aren't the same as the prev, it must
|
|
|
|
|
// have changed direction
|
|
|
|
|
if level_state != prev_state {
|
|
|
|
|
return false;
|
2025-05-25 16:02:23 -05:00
|
|
|
}
|
|
|
|
|
|
2025-05-25 17:15:31 -05:00
|
|
|
// Setup for next iteration
|
|
|
|
|
prev_state = level_state;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
2025-05-25 16:02:23 -05:00
|
|
|
}
|
|
|
|
|
|
2025-05-25 17:15:31 -05:00
|
|
|
// 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);
|
|
|
|
|
// dbg!(modified_report);
|
|
|
|
|
|
|
|
|
|
// 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)) => {
|
|
|
|
|
// let diff = curr
|
|
|
|
|
// },
|
|
|
|
|
// (Some(prev), Some(curr), Some(next)) => (),
|
|
|
|
|
// (Some(prev), Some(curr), None) => (),
|
|
|
|
|
// _ => panic!("This should never happen!"),
|
|
|
|
|
// }
|
|
|
|
|
// states.push(state);
|
|
|
|
|
// }
|
|
|
|
|
|
2025-05-25 16:02:23 -05:00
|
|
|
fn main() -> Result<(), Box<dyn Error>> {
|
|
|
|
|
// Handle command input
|
|
|
|
|
let args: Vec<String> = 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 = 0;
|
|
|
|
|
for line in input_reader.lines() {
|
|
|
|
|
let line = line?;
|
|
|
|
|
let parsed_report: Vec<i64> = parse_report(&line)?;
|
2025-05-25 17:15:31 -05:00
|
|
|
if is_report_safe(parsed_report) {
|
2025-05-25 16:02:23 -05:00
|
|
|
accumulator += 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
println!("Number of SAFE reports: {}", accumulator);
|
|
|
|
|
|
|
|
|
|
Ok(())
|
2025-05-25 13:09:21 -05:00
|
|
|
}
|