diff --git a/src/day02/mod.rs b/src/day02/mod.rs index 68dabe2..912e435 100644 --- a/src/day02/mod.rs +++ b/src/day02/mod.rs @@ -5,7 +5,8 @@ use std::{error::Error, fs}; /// # Errors /// /// This function will return an error if the file cannot be read or if the input is invalid. -pub fn solve_day02(path: &str) -> Result> { +#[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)] +pub fn solve_day02(path: &str) -> Result<(i32, i32), Box> { let content = fs::read_to_string(path)?; let data: Vec> = content @@ -16,18 +17,126 @@ pub fn solve_day02(path: &str) -> Result> { .collect::, _>>() }) .collect::, _>>()?; - Ok(0) + + let result = verify_all_reports(&data); + let result1 = result + .iter() + .filter(|safety| *safety != &Safety::Unsafe) + .count() as i32; + + let result = verify_tolerance(&data); + let result2 = result + .iter() + .filter(|safety| *safety != &Safety::Unsafe) + .count() as i32; + + Ok((result1, result2)) } -fn calculate_report_safety(data: &Vec>) -> i32 { - data.iter() - .map(|reports| { - for report in reports { - todo!("Implement this") +#[allow(dead_code)] +#[derive(Debug, Clone, PartialEq, Eq)] +enum Safety { + Safe, + Unsafe, +} + +#[allow(dead_code)] +fn verify_all_reports(reports: &[Vec]) -> Vec { + reports + .iter() + .map(|report| verify_reports(report)) + .collect() +} + +#[allow(dead_code)] +fn verify_tolerance(reports: &[Vec]) -> Vec { + reports + .iter() + // .filter(|report| verify_reports(report) == Safety::Unsafe) + .map(|report| { + let rep = verify_reports(report); + + if rep == Safety::Safe { + return Safety::Safe; + } + + if report + .iter() + .enumerate() + .map(|(index, _)| { + let temp: Vec = report + .iter() + .enumerate() + .filter(|(i, _)| *i != index) + .map(|(_, r)| *r) + .collect(); + // dbg!(&report, index, &temp); + verify_reports(&temp) + }) + .any(|r| r == Safety::Safe) + { + Safety::Safe + } else { + Safety::Unsafe } - 0 }) - .sum() + .collect() +} + +#[allow(dead_code)] +fn verify_reports(reports: &[i32]) -> Safety { + const MAX: i32 = 3; + const MIN: i32 = 1; + + for (index, report) in reports.iter().enumerate() { + if index == 0 { + continue; + } + + let previous_report = reports[index - 1]; + if index == reports.len() - 1 { + match (*report, previous_report) { + (r, p) if r > p => { + let level = r - p; + if !(MIN..=MAX).contains(&level) { + return Safety::Unsafe; + } + } + (r, p) if r < p => { + let level = p - r; + if !(MIN..=MAX).contains(&level) { + return Safety::Unsafe; + } + } + (r, p) if r == p => return Safety::Unsafe, + _ => (), + } + return Safety::Safe; + } + let next_report = reports[index + 1]; + + match (*report, previous_report, next_report) { + (r, p, n) if r > p && r < n => { + let level = r - p; + if !(MIN..=MAX).contains(&level) { + return Safety::Unsafe; + } + } + (r, p, n) if r < p && r > n => { + let level = p - r; + if !(MIN..=MAX).contains(&level) { + return Safety::Unsafe; + } + } + (r, p, n) if (r < p && r < n) || (r > p && r > n) => { + return Safety::Unsafe; + } + (r, p, n) if r == p || r == n => return Safety::Unsafe, + _ => (), + } + } + + Safety::Safe } #[cfg(test)] @@ -35,7 +144,7 @@ mod test { use super::*; #[test] - fn test_day02() { + fn test_day02_part_one() { let input = vec![ vec![7, 6, 4, 2, 1], vec![1, 2, 7, 8, 9], @@ -45,8 +154,62 @@ mod test { vec![1, 3, 6, 7, 9], ]; - let want = 2; + let want = Safety::Safe; + let got = verify_reports(&input[0]); - assert_eq!(calculate_report_safety(&input), want); + assert_eq!(want, got); + + let want = Safety::Unsafe; + + let got = verify_reports(&input[1]); + assert_eq!(want, got); + let got = verify_reports(&input[2]); + assert_eq!(want, got); + let got = verify_reports(&input[3]); + assert_eq!(want, got); + let got = verify_reports(&input[4]); + assert_eq!(want, got); + + let want = 2; + let got = verify_all_reports(&input); + assert_eq!( + want, + got.iter() + .filter(|safety| *safety != &Safety::Unsafe) + .count() + ); + + let got = verify_all_reports(&input); + + assert_eq!( + want, + got.iter() + .filter(|safety| *safety != &Safety::Unsafe) + .count() + ); + } + + #[test] + fn test_day02_part_two() { + let input = vec![ + vec![7, 6, 4, 2, 1], + vec![1, 2, 7, 8, 9], + vec![9, 7, 6, 2, 1], + vec![1, 3, 2, 4, 5], + vec![8, 6, 4, 4, 1], + vec![1, 3, 6, 7, 9], + ]; + + let want = 4; + + let got = verify_tolerance(&input); + assert_eq!(input.len(), got.len()); + + assert_eq!( + want, + got.iter() + .filter(|safety| *safety != &Safety::Unsafe) + .count() + ); } } diff --git a/src/main.rs b/src/main.rs index 0911658..218de46 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -use adventofcode_24::day01::solve_day01; +use adventofcode_24::{day01::solve_day01, day02::solve_day02}; use clap::{Arg, Command}; fn main() { @@ -11,6 +11,11 @@ fn main() { .short('1') .help("Path to Day 01 Input file"), ) + .arg( + Arg::new("day02") + .short('2') + .help("Path to Day 02 Input file"), + ) .get_matches(); if let Some(file) = matches.get_one::("day01") { @@ -19,4 +24,15 @@ fn main() { Err(e) => eprintln!("{e}"), } } + + if let Some(file) = matches.get_one::("day02") { + match solve_day02(file) { + Ok((r1, r2)) => { + println!( + "Result of Day 02:\nSafe Reports: {r1}\nSafe Reports with tolerance: {r2}" + ); + } + Err(e) => eprintln!("{e}"), + } + } }