year2025/
day07.rs

1use utils::prelude::*;
2
3/// Counting splitting paths in a grid.
4#[derive(Clone, Debug)]
5pub struct Day07 {
6    part1: u64,
7    part2: u64,
8}
9
10impl Day07 {
11    pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
12        let mut seen_start = false;
13        let mut timeline_counts = Vec::new();
14        let mut split_count = 0;
15
16        for line in input.lines() {
17            if timeline_counts.is_empty() {
18                // Add 1 padding column on each side so c +- 1 below is always safe
19                timeline_counts.resize(line.len() + 2, 0);
20            } else if timeline_counts.len() != line.len() + 2 {
21                return Err(InputError::new(
22                    input,
23                    line,
24                    "expected consistent line lengths",
25                ));
26            }
27
28            for (i, b) in line.bytes().enumerate() {
29                let c = i + 1;
30
31                match b {
32                    b'^' if timeline_counts[c] > 0 => {
33                        timeline_counts[c - 1] += timeline_counts[c];
34                        timeline_counts[c + 1] += timeline_counts[c];
35                        timeline_counts[c] = 0;
36                        split_count += 1;
37                    }
38                    b'.' | b'^' => {}
39                    b'S' if !seen_start => {
40                        timeline_counts[c] += 1;
41                        seen_start = true;
42                    }
43                    b'S' => return Err(InputError::new(input, line, "expected one 'S'")),
44                    _ => return Err(InputError::new(input, line, "expected '.', '^' or 'S'")),
45                }
46            }
47        }
48
49        Ok(Self {
50            part1: split_count,
51            part2: timeline_counts.iter().sum(),
52        })
53    }
54
55    #[must_use]
56    pub fn part1(&self) -> u64 {
57        self.part1
58    }
59
60    #[must_use]
61    pub fn part2(&self) -> u64 {
62        self.part2
63    }
64}
65
66examples!(Day07 -> (u64, u64) [
67    {file: "day07_example0.txt", part1: 21, part2: 40},
68]);