From a2b812b34a2acd7eafe09fcedd9c9cb3c074b116 Mon Sep 17 00:00:00 2001 From: Greg Burri Date: Tue, 3 Dec 2024 18:08:41 +0100 Subject: [PATCH] Day 02 --- src/day02.rs | 134 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/days.rs | 10 ++++ src/main.rs | 4 +- 3 files changed, 146 insertions(+), 2 deletions(-) create mode 100644 src/day02.rs diff --git a/src/day02.rs b/src/day02.rs new file mode 100644 index 0000000..1b88e99 --- /dev/null +++ b/src/day02.rs @@ -0,0 +1,134 @@ +use std::io::BufRead; + +use itertools::{self, Itertools}; + +type Reports = Vec>; + +pub fn read_reports(reader: R) -> Reports +where + R: BufRead, +{ + let mut reports = Vec::>::new(); + for l in reader.lines() { + reports.push( + l.unwrap() + .split(' ') + .map(|level| level.parse::().unwrap()) + .collect(), + ); + } + reports +} + +pub fn nb_of_safe_reports(reports: &Reports) -> i32 { + reports.iter().fold(0, |nb, levels| { + let sign_first = (levels[0] - levels[1]).signum(); + for (a, b) in levels.iter().tuple_windows() { + let d = a - b; + if d.signum() != sign_first || d.abs() == 0 || d.abs() > 3 { + return nb; + } + } + nb + 1 + }) +} + +pub fn nb_of_safe_reports_with_tolerance(reports: &Reports) -> i32 { + reports.iter().fold(0, |nb, levels| { + let mut diff: Vec = levels.iter().tuple_windows().map(|(a, b)| b - a).collect(); + if diff.iter().map(|v| v.signum()).sum::() < 0 { + for v in diff.iter_mut() { + *v = *v * -1; + } + } + + let pos_negs = diff.iter().positions(|v| *v <= 0).collect::>(); + + if pos_negs.len() > 1 { + return nb; + } + if pos_negs.len() == 1 { + let p = pos_negs[0]; + // First diff. + if p == 0 { + if diff[p + 1] > 3 { + diff[p + 1] += diff[p]; + } + // Last diff. + } else if p == diff.len() - 1 { + if diff[p - 1] > 3 { + diff[p - 1] += diff[p]; + } + } else { + if diff[p - 1] > diff[p + 1] { + diff[p - 1] += diff[p]; + if diff[p - 1] == 0 { + return nb; + } + } else { + diff[p + 1] += diff[p]; + if diff[p + 1] == 0 { + return nb; + } + } + } + } + + let pos_too_big = diff.iter().positions(|v| *v > 3).collect::>(); + if pos_too_big.len() > 1 + || pos_too_big.len() == 1 && pos_negs.len() == 1 + || pos_too_big.len() == 1 && pos_too_big[0] != 0 && pos_too_big[0] != diff.len() - 1 + { + return nb; + } + + nb + 1 + }) +} + +#[cfg(test)] +mod tests { + use super::*; + + static REPORTS: &str = "7 6 4 2 1 +1 2 7 8 9 +9 7 6 2 1 +1 3 2 4 5 +8 6 4 4 1 +1 3 6 7 9"; + + #[test] + fn part1() { + let reports = read_reports(REPORTS.as_bytes()); + assert_eq!(nb_of_safe_reports(&reports), 2); + } + + #[test] + fn part2() { + let reports = read_reports(REPORTS.as_bytes()); + assert_eq!(nb_of_safe_reports_with_tolerance(&reports), 4); + } + + static VALID_REPORTS: &str = "1 4 -10 5 +1 -10 4 5 +-10 1 4 5 +1 4 5 -10"; + + static INVALID_REPORTS: &str = "8 4 8 4 +4 8 4 8 +0 4 2 6 +6 2 4 0 +8 8 8 8"; + + #[test] + fn part2_additional_valid_reports() { + let reports = read_reports(VALID_REPORTS.as_bytes()); + assert_eq!(nb_of_safe_reports_with_tolerance(&reports), 4); + } + + #[test] + fn part2_additional_invalid_reports() { + let reports = read_reports(INVALID_REPORTS.as_bytes()); + assert_eq!(nb_of_safe_reports_with_tolerance(&reports), 0); + } +} diff --git a/src/days.rs b/src/days.rs index 5c6ed4b..03e4e34 100644 --- a/src/days.rs +++ b/src/days.rs @@ -11,3 +11,13 @@ pub fn day01() -> String { day01::similarity_score(&ids1, &ids2) ) } + +pub fn day02() -> String { + let f = fs::File::open("data/day02.input").unwrap(); + let reports = day02::read_reports(BufReader::new(f)); + format!( + "part1: {}, part2: {}", + day02::nb_of_safe_reports(&reports), + day02::nb_of_safe_reports_with_tolerance(&reports) + ) +} diff --git a/src/main.rs b/src/main.rs index d268f58..15bf0ef 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,7 @@ use clap::Parser; use rayon::prelude::*; mod day01; -// mod day02; +mod day02; // mod day03; // mod day04; // mod day05; @@ -44,7 +44,7 @@ fn main() { let days: Vec String> = vec![ days::day01, - // days::day02, + days::day02, // days::day03, // days::day04, // days::day05, -- 2.45.2