Day 02
authorGreg Burri <greg.burri@gmail.com>
Tue, 3 Dec 2024 17:08:41 +0000 (18:08 +0100)
committerGreg Burri <greg.burri@gmail.com>
Tue, 3 Dec 2024 17:08:41 +0000 (18:08 +0100)
src/day02.rs [new file with mode: 0644]
src/days.rs
src/main.rs

diff --git a/src/day02.rs b/src/day02.rs
new file mode 100644 (file)
index 0000000..1b88e99
--- /dev/null
@@ -0,0 +1,134 @@
+use std::io::BufRead;
+
+use itertools::{self, Itertools};
+
+type Reports = Vec<Vec<i32>>;
+
+pub fn read_reports<R>(reader: R) -> Reports
+where
+    R: BufRead,
+{
+    let mut reports = Vec::<Vec<i32>>::new();
+    for l in reader.lines() {
+        reports.push(
+            l.unwrap()
+                .split(' ')
+                .map(|level| level.parse::<i32>().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<i32> = levels.iter().tuple_windows().map(|(a, b)| b - a).collect();
+        if diff.iter().map(|v| v.signum()).sum::<i32>() < 0 {
+            for v in diff.iter_mut() {
+                *v = *v * -1;
+            }
+        }
+
+        let pos_negs = diff.iter().positions(|v| *v <= 0).collect::<Vec<usize>>();
+
+        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::<Vec<usize>>();
+        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);
+    }
+}
index 5c6ed4b..03e4e34 100644 (file)
@@ -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)
+    )
+}
index d268f58..15bf0ef 100644 (file)
@@ -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<fn() -> String> = vec![
         days::day01,
-        // days::day02,
+        days::day02,
         // days::day03,
         // days::day04,
         // days::day05,