248 lines
6.5 KiB
Rust
248 lines
6.5 KiB
Rust
// reads the input and puts into a matrix.
|
|
// each inner vector is a row of the matrix
|
|
fn read_input() -> Vec<Vec<u32>> {
|
|
let input = std::fs::read_to_string("./input.txt").unwrap();
|
|
|
|
let mut trees = vec![];
|
|
for line in input.lines() {
|
|
let mut row = vec![];
|
|
for tree in line.chars() {
|
|
// parse char to u32
|
|
let tree_height = tree.to_digit(10).unwrap();
|
|
row.push(tree_height);
|
|
}
|
|
|
|
trees.push(row);
|
|
}
|
|
|
|
trees
|
|
}
|
|
|
|
fn count_perimeter(num_rows: usize, num_cols: usize) -> u32 {
|
|
((num_rows * 2) + (num_cols * 2) - 4) as u32
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
struct Tree {
|
|
height: u32,
|
|
max_right: u32,
|
|
max_left: u32,
|
|
max_up: u32,
|
|
max_down: u32,
|
|
is_perimeter: bool,
|
|
}
|
|
|
|
impl Tree {
|
|
pub fn is_visible_somewhere(&self) -> bool {
|
|
if self.is_perimeter {
|
|
return true;
|
|
}
|
|
|
|
self.height > self.max_right
|
|
|| self.height > self.max_left
|
|
|| self.height > self.max_up
|
|
|| self.height > self.max_down
|
|
}
|
|
|
|
pub fn scenic_score(&self) -> u32 {
|
|
0
|
|
}
|
|
}
|
|
|
|
// takes in grid of trees and returns a grid of trees
|
|
fn process_trees(trees: &[&[u32]]) -> Vec<Tree> {
|
|
let mut processed_trees = vec![];
|
|
|
|
for (row_index, row) in trees.iter().enumerate() {
|
|
for (col_index, tree_height) in row.iter().enumerate() {
|
|
if col_index == 0
|
|
|| row_index == 0
|
|
|| col_index == row.len() - 1
|
|
|| row_index == trees.len() - 1
|
|
{
|
|
let processed_tree = Tree {
|
|
height: *tree_height,
|
|
max_right: 0,
|
|
max_left: 0,
|
|
max_up: 0,
|
|
max_down: 0,
|
|
is_perimeter: true,
|
|
};
|
|
|
|
processed_trees.push(processed_tree);
|
|
continue;
|
|
}
|
|
|
|
// get max of all trees to the right
|
|
let max_right = row[(col_index + 1)..].iter().max().unwrap();
|
|
let max_left = row[..col_index].iter().max().unwrap();
|
|
let max_up = trees[..row_index]
|
|
.iter()
|
|
.map(|row| row[col_index])
|
|
.max()
|
|
.unwrap();
|
|
let max_down = trees[(row_index + 1)..]
|
|
.iter()
|
|
.map(|row| row[col_index])
|
|
.max()
|
|
.unwrap();
|
|
|
|
let processed_tree = Tree {
|
|
height: *tree_height,
|
|
max_right: *max_right,
|
|
max_left: *max_left,
|
|
max_up,
|
|
max_down,
|
|
is_perimeter: false,
|
|
};
|
|
|
|
processed_trees.push(processed_tree);
|
|
}
|
|
}
|
|
|
|
processed_trees
|
|
}
|
|
|
|
fn count_visible_trees(trees: Vec<Tree>) -> u32 {
|
|
let mut visible_trees = 0;
|
|
|
|
for tree in trees {
|
|
if tree.is_visible_somewhere() {
|
|
visible_trees += 1;
|
|
}
|
|
}
|
|
|
|
visible_trees
|
|
}
|
|
|
|
// takes in grid of trees and returns a grid of trees
|
|
fn process_trees_scenic(trees: &[&[u32]]) -> u32 {
|
|
let mut max_scenic_score = u32::MIN;
|
|
|
|
for (row_index, row) in trees.iter().enumerate() {
|
|
for (col_index, tree_height) in row.iter().enumerate() {
|
|
// count number of trees to the right until we hit the
|
|
// end or a tree that is taller than the current tree
|
|
let mut right = 0;
|
|
for (index, tree) in row[(col_index + 1)..].iter().enumerate() {
|
|
right += 1;
|
|
|
|
if tree >= tree_height {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// count number of trees to the left
|
|
let mut left = 0;
|
|
for (index, tree) in row[..col_index].iter().rev().enumerate() {
|
|
left += 1;
|
|
|
|
if tree >= tree_height {
|
|
break;
|
|
}
|
|
}
|
|
|
|
let mut up = 0;
|
|
for (index, row) in trees[..row_index].iter().rev().enumerate() {
|
|
up += 1;
|
|
|
|
if row[col_index] >= *tree_height {
|
|
break;
|
|
}
|
|
}
|
|
|
|
let mut down = 0;
|
|
for (index, row) in trees[(row_index + 1)..].iter().enumerate() {
|
|
down += 1;
|
|
|
|
if row[col_index] >= *tree_height {
|
|
break;
|
|
}
|
|
}
|
|
|
|
let scenic_score = right * left * up * down;
|
|
if scenic_score as u32 > max_scenic_score {
|
|
max_scenic_score = scenic_score as u32;
|
|
}
|
|
|
|
println!(
|
|
"current_tree: {:?}, right: {:?}, left: {:?}, up: {:?}, down: {:?}, scenic_score: {:?}",
|
|
tree_height, right, left, up, down, scenic_score
|
|
);
|
|
}
|
|
}
|
|
|
|
max_scenic_score
|
|
}
|
|
|
|
fn main() {
|
|
println!("Hello, world!");
|
|
|
|
let trees = read_input();
|
|
|
|
println!(
|
|
"how many rows {:?}, how many columns {:?}",
|
|
trees.len(),
|
|
trees[0].len()
|
|
);
|
|
|
|
println!(
|
|
"perimeter is {:?}",
|
|
count_perimeter(trees.len(), trees[0].len())
|
|
);
|
|
|
|
let trees: Vec<&[u32]> = trees.iter().map(|row| row.as_slice()).collect();
|
|
let processed_trees = process_trees(&trees);
|
|
|
|
let visible_trees = count_visible_trees(processed_trees);
|
|
|
|
println!("visible trees: {:?}", visible_trees);
|
|
|
|
let max_scenic_score = process_trees_scenic(&trees);
|
|
println!("max scenic score: {:?}", max_scenic_score);
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn part_one() {}
|
|
|
|
#[test]
|
|
fn test_count_perimeter() {
|
|
assert_eq!(count_perimeter(3, 3), 8_u32);
|
|
assert_eq!(count_perimeter(5, 5), 16_u32);
|
|
}
|
|
|
|
#[test]
|
|
fn test_part_one() {
|
|
// mimic the above grid into a vec of vecs
|
|
let trees = vec![
|
|
vec![3, 0, 3, 7, 3],
|
|
vec![2, 5, 5, 1, 2],
|
|
vec![6, 5, 3, 3, 2],
|
|
vec![3, 3, 5, 4, 9],
|
|
vec![3, 5, 3, 9, 0],
|
|
];
|
|
|
|
let trees: Vec<&[u32]> = trees.iter().map(|row| row.as_slice()).collect();
|
|
let processed_trees = process_trees(&trees);
|
|
assert_eq!(count_visible_trees(processed_trees), 21);
|
|
}
|
|
|
|
#[test]
|
|
fn test_part_two() {
|
|
let trees = vec![
|
|
vec![3, 0, 3, 7, 3],
|
|
vec![2, 5, 5, 1, 2],
|
|
vec![6, 5, 3, 3, 2],
|
|
vec![3, 3, 5, 4, 9],
|
|
vec![3, 5, 3, 9, 0],
|
|
];
|
|
|
|
let trees: Vec<&[u32]> = trees.iter().map(|row| row.as_slice()).collect();
|
|
assert_eq!(process_trees_scenic(&trees), 8);
|
|
}
|
|
}
|