126 lines
3.2 KiB
Rust
126 lines
3.2 KiB
Rust
#![feature(iterator_try_collect, absolute_path, hash_set_entry)]
|
|
|
|
use std::fs;
|
|
use std::io::{self, BufRead};
|
|
|
|
use grid::Grid;
|
|
use take_until::TakeUntilExt;
|
|
|
|
struct Tree {
|
|
height: u8,
|
|
visible: bool,
|
|
}
|
|
|
|
impl Tree {
|
|
fn new(height: u8) -> Self {
|
|
Tree {
|
|
height,
|
|
visible: false,
|
|
}
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
let filename = "etc/p08.txt";
|
|
let file = fs::File::open(filename).expect("Can't open file");
|
|
let mut count: Option<usize> = None;
|
|
let vec: Vec<Tree> = io::BufReader::new(file)
|
|
.lines()
|
|
.flatten()
|
|
.flat_map(|l| {
|
|
count.get_or_insert_with(|| l.chars().count());
|
|
l.chars()
|
|
.map(|c| Tree::new(c.to_digit(10).unwrap() as u8))
|
|
.collect::<Vec<Tree>>()
|
|
})
|
|
.collect();
|
|
|
|
let mut grid = Grid::from_vec(vec, count.unwrap());
|
|
println!("PART 1 ---------------");
|
|
part1(&mut grid);
|
|
println!("\nPART 2 ---------------");
|
|
part2(&grid);
|
|
}
|
|
|
|
fn part1(grid: &mut Grid<Tree>) {
|
|
fn height_pass(acc: u8, t: &mut Tree) -> u8 {
|
|
if t.height > acc {
|
|
t.visible = true;
|
|
}
|
|
t.height.max(acc)
|
|
}
|
|
|
|
grid.iter_col_mut(0).for_each(|t| t.visible = true);
|
|
grid.iter_col_mut(grid.cols() - 1)
|
|
.for_each(|t| t.visible = true);
|
|
grid.iter_row_mut(0).for_each(|t| t.visible = true);
|
|
grid.iter_row_mut(grid.rows() - 1)
|
|
.for_each(|t| t.visible = true);
|
|
|
|
for i in 0..grid.cols() {
|
|
grid.iter_col_mut(i).fold(0, height_pass);
|
|
grid.iter_col_mut(i).rev().fold(0, height_pass);
|
|
}
|
|
for i in 0..grid.rows() {
|
|
grid.iter_row_mut(i).fold(0, height_pass);
|
|
grid.iter_row_mut(i).rev().fold(0, height_pass);
|
|
}
|
|
|
|
dbg!(grid.iter().filter(|t| t.visible).count());
|
|
}
|
|
|
|
fn scenic_score(tree: &Tree, grid: &Grid<Tree>, (row, col): (usize, usize)) -> usize {
|
|
fn count_visible<'a>(tree: &Tree, iter: impl Iterator<Item = Option<&'a Tree>>) -> usize {
|
|
iter.flatten()
|
|
.take_until(|t| t.height >= tree.height)
|
|
.count()
|
|
}
|
|
|
|
let (rows, cols) = grid.size();
|
|
|
|
let a = count_visible(tree, (0..row).rev().map(|r| grid.get(r, col)));
|
|
let b = count_visible(tree, (row + 1..rows).map(|r| grid.get(r, col)));
|
|
let c = count_visible(tree, (0..col).rev().map(|c| grid.get(row, c)));
|
|
let d = count_visible(tree, (col + 1..cols).map(|c| grid.get(row, c)));
|
|
|
|
a * b * c * d
|
|
}
|
|
|
|
fn part2(grid: &Grid<Tree>) {
|
|
let cols = grid.cols();
|
|
dbg!(grid
|
|
.iter()
|
|
.enumerate()
|
|
.map(|(i, t)| scenic_score(t, grid, (i / cols, i % cols)))
|
|
.max()
|
|
.unwrap());
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use grid::grid;
|
|
|
|
#[test]
|
|
fn small_grid() {
|
|
let grid = grid![
|
|
[3, 0, 3, 7, 3]
|
|
[2, 5, 5, 1, 2]
|
|
[6, 5, 3, 3, 2]
|
|
[3, 3, 5, 4, 9]
|
|
[3, 5, 3, 9, 0]
|
|
];
|
|
let vec: Vec<Tree> = grid.iter().map(|n| Tree::new(*n)).collect();
|
|
let grid = Grid::from_vec(vec, 5);
|
|
|
|
let scores: Vec<usize> = grid
|
|
.iter()
|
|
.enumerate()
|
|
.map(|(i, t)| scenic_score(t, &grid, (i / 5, i % 5)))
|
|
.collect();
|
|
dbg!(&scores);
|
|
|
|
assert_eq!(8, *scores.iter().max().unwrap());
|
|
}
|
|
}
|