summaryrefslogtreecommitdiffstats
path: root/day08a/src/main.rs
blob: 510ccb7b8441caf7bfa4fb2b1bdd7d1e7d523470 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
/// --- Day 8: Treetop Tree House ---
///
/// The expedition comes across a peculiar patch of tall trees all planted carefully in a grid.
/// The Elves explain that a previous expedition planted these trees as a reforestation
/// effort.  Now, they're curious if this would be a good location for a tree house.
///
/// First, determine whether there is enough tree cover here to keep a tree house hidden.  To do
/// this, you need to count the number of trees that are visible from outside the grid when looking
/// directly along a row or column.
///
/// The Elves have already launched a quadcopter to generate a map with the height of each tree
/// (your puzzle input). For example:
///
/// ```
/// 30373
/// 25512
/// 65332
/// 33549
/// 35390
/// ```
///
/// Each tree is represented as a single digit whose value is its height, where 0 is the shortest
/// and 9 is the tallest.
///
/// A tree is visible if all of the other trees between it and an edge of the grid are shorter than
/// it.  Only consider trees in the same row or column; that is, only look up, down, left, or right
/// from any given tree.
///
/// All of the trees around the edge of the grid are visible - since they are already on the edge,
/// there are no trees to block the view.  In this example, that only leaves the interior nine
/// trees to consider:
///
///     The top-left 5 is visible from the left and top. (It isn't visible from the right or bottom
///     since other trees of height 5 are in the way.)
///     The top-middle 5 is visible from the top and right.
///     The top-right 1 is not visible from any direction; for it to be visible, there would need
///     to only be trees of height 0 between it and an edge.
///     The left-middle 5 is visible, but only from the right.
///     The center 3 is not visible from any direction; for it to be visible, there would need to
///     be only trees of at most height 2 between it and an edge.
///     The right-middle 3 is visible from the right.
///     In the bottom row, the middle 5 is visible, but the 3 and 4 are not.
///
/// With 16 trees visible on the edge and another 5 visible in the interior, a total of 21 trees
/// are visible in this arrangement.
///
/// Consider your map; how many trees are visible from outside the grid?
use clap::Parser;
use itertools::Itertools;

use std::fs::File;
use std::io::prelude::*;
use std::io::BufReader;
use std::path::PathBuf;

const FILEPATH: &'static str = "examples/input.txt";

#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
struct Cli {
    #[clap(short, long, default_value = FILEPATH)]
    file: PathBuf,
}

#[derive(Clone)]
struct Visibility {
    visible: bool,
    top: u8,
    bottom: u8,
    left: u8,
    right: u8,
}

impl Visibility {
    fn new() -> Self {
        Self {
            visible: false,
            top: 0,
            bottom: 0,
            left: 0,
            right: 0,
        }
    }
}

fn main() {
    let args = Cli::parse();

    let file = File::open(&args.file).unwrap();
    let reader = BufReader::new(file);
    let grid = reader
        .lines()
        .map(|l| {
            l.unwrap()
                .chars()
                .map(|c| c.to_digit(10).unwrap() as u8)
                .collect_vec()
        })
        .collect_vec();

    let xdim = grid.len();
    let ydim = grid[0].len();

    let mut vis_grid: Vec<Vec<Visibility>> = Vec::new();
    vis_grid.resize(xdim, vec![Visibility::new(); ydim]);

    for idx in 0..xdim {
        for idy in 0..ydim {
            let tree = grid[idx][idy];
            match (idy, idx) {
                (0, 0) => {
                    let vis = &mut vis_grid[idx][idy];
                    vis.visible = true;
                    vis.left = tree;
                    vis.top = tree;
                }
                (0, _) => {
                    let vis = &mut vis_grid[idx][idy];
                    vis.visible = true;
                    vis.left = tree;
                }
                (_, 0) => {
                    let vis = &mut vis_grid[idx][idy];
                    vis.visible = true;
                    vis.top = tree;
                }
                (idy, idx) => {
                    let lhs_vis = vis_grid[idx][idy - 1].left;
                    let top_vis = vis_grid[idx - 1][idy].top;

                    let vis = &mut vis_grid[idx][idy];
                    if lhs_vis < tree {
                        vis.left = tree;
                        vis.visible = true;
                    } else {
                        vis.left = lhs_vis;
                    }

                    if top_vis < tree {
                        vis.top = tree;
                        vis.visible = true;
                    } else {
                        vis.top = top_vis;
                    }

                    if lhs_vis >= tree && top_vis >= tree {
                        vis.visible = false;
                    }
                }
            }
        }
    }

    for idx in (0..xdim).rev() {
        for idy in (0..ydim).rev() {
            let tree = grid[idx][idy];
            match (idy, idx) {
                (x, y) if (x == ydim - 1 && y == xdim - 1) => {
                    let vis = &mut vis_grid[idx][idy];
                    vis.visible = true;
                    vis.right = tree;
                    vis.bottom = tree;
                }
                (x, _) if x == ydim - 1 => {
                    let vis = &mut vis_grid[idx][idy];
                    vis.visible = true;
                    vis.right = tree;
                }
                (_, y) if y == xdim - 1 => {
                    let vis = &mut vis_grid[idx][idy];
                    vis.visible = true;
                    vis.bottom = tree;
                }
                (idy, idx) => {
                    let rhs_vis = vis_grid[idx][idy + 1].right;
                    let bottom_vis = vis_grid[idx + 1][idy].bottom;

                    let vis = &mut vis_grid[idx][idy];
                    if rhs_vis < tree {
                        vis.right = tree;
                        vis.visible = true;
                    } else {
                        vis.right = rhs_vis;
                    }

                    if bottom_vis < tree {
                        vis.bottom = tree;
                        vis.visible = true;
                    } else {
                        vis.bottom = bottom_vis;
                    }
                }
            }
        }
    }

    let res: u32 = vis_grid
        .into_iter()
        .flatten()
        .map(|v| if v.visible { 1 } else { 0 })
        .sum();
    println!("{res:?}");
}