advent_of_code/year2022/
day08.rs

1use crate::input::Input;
2
3pub fn solve(input: &Input) -> Result<usize, String> {
4    let grid = input
5        .text
6        .bytes()
7        .filter(u8::is_ascii_digit)
8        .map(|b| b - b'0')
9        .collect::<Vec<_>>();
10
11    let grid_size = (grid.len() as f64).sqrt() as usize;
12    if grid_size * grid_size != grid.len() {
13        return Err("Non-rectangular grid".to_string());
14    }
15
16    let mut num_visible = 0;
17    let mut best_scenic_score = 0;
18
19    'start: for start in 0..grid.len() {
20        let mut scenic_score = 1;
21        'stride: for (stride, steps) in [
22            (-1, start % grid_size),
23            (1, grid_size - start % grid_size - 1),
24            (-(grid_size as i32), start / grid_size),
25            ((grid_size as i32), grid_size - start / grid_size - 1),
26        ] {
27            let mut position = start as i32;
28            let start_height = grid[start];
29
30            for step in 1..=steps {
31                position += stride;
32                let height_at_position = grid[position as usize];
33                if height_at_position >= start_height {
34                    scenic_score *= step;
35                    continue 'stride;
36                }
37            }
38
39            if input.is_part_one() {
40                num_visible += 1;
41                continue 'start;
42            }
43            scenic_score *= steps;
44        }
45
46        best_scenic_score = best_scenic_score.max(scenic_score);
47    }
48
49    Ok(input.part_values(num_visible, best_scenic_score))
50}
51
52#[test]
53pub fn tests() {
54    use crate::input::{test_part_one, test_part_two};
55
56    let test_input = "30373
5725512
5865332
5933549
6035390";
61    test_part_one!(test_input => 21);
62    test_part_two!(test_input => 8);
63
64    let real_input = include_str!("day08_input.txt");
65    test_part_one!(real_input => 1_672);
66    test_part_two!(real_input => 327_180);
67}