Skip to main content

aoc/year2024/
day02.rs

1//! # Red-Nosed Reports
2//!
3//! Computes both parts simultaneously. Each pair of levels is converted into deltas of
4//! either +1, -1 or 0. For example:
5//!
6//! * `1 3 6 7 9` => `+1 +1 +1 +1`
7//! * `9 7 6 2 1` => `-1 -1 0 -1`
8//!
9//! If the sum of all deltas equals ±4, then we know that all levels are increasing or
10//! decreasing. Any other value indicates either mixed up and down transitions or levels that
11//! are too far apart.
12//!
13//! For part two, we remove each pair of deltas (or single delta at each end) then replace with
14//! the delta from the new neighbors on either side.
15use crate::util::parse::*;
16
17type Input = (u32, u32);
18
19/// Minimize allocation to only a single `vec` reused for each report.
20pub fn parse(input: &str) -> Input {
21    let mut report = Vec::new();
22
23    input.lines().fold((0, 0), |(part_one, part_two), line| {
24        report.clear();
25        report.extend(line.iter_signed::<i32>());
26
27        let (p1, p2) = check(&report);
28        (part_one + p1, part_two + p2)
29    })
30}
31
32pub fn part1(input: &Input) -> u32 {
33    input.0
34}
35
36pub fn part2(input: &Input) -> u32 {
37    input.1
38}
39
40fn check(report: &[i32]) -> (u32, u32) {
41    let end = report.len() - 1;
42    let target = end as i32;
43    let score: i32 = report.array_windows().map(|&[a, b]| delta(a, b)).sum();
44
45    if score.abs() == target {
46        return (1, 1);
47    }
48
49    let dampened = (0..=end).any(|i| {
50        let mut score = score;
51
52        // Snip out each level and replace with a new level computed from neighbors on either side.
53        if i > 0 {
54            score -= delta(report[i - 1], report[i]);
55        }
56        if i < end {
57            score -= delta(report[i], report[i + 1]);
58        }
59        if i > 0 && i < end {
60            score += delta(report[i - 1], report[i + 1]);
61        }
62
63        score.abs() == target - 1
64    });
65
66    (0, u32::from(dampened))
67}
68
69/// Convert each pair of levels to either +1 for increase, -1 for decrease or 0 for invalid range.
70fn delta(a: i32, b: i32) -> i32 {
71    match b - a {
72        1..=3 => 1,
73        -3..=-1 => -1,
74        _ => 0,
75    }
76}