#![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 = None; let vec: Vec = 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::>() }) .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) { 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, (row, col): (usize, usize)) -> usize { fn count_visible<'a>(tree: &Tree, iter: impl Iterator>) -> 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) { 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 = grid.iter().map(|n| Tree::new(*n)).collect(); let grid = Grid::from_vec(vec, 5); let scores: Vec = grid .iter() .enumerate() .map(|(i, t)| scenic_score(t, &grid, (i / 5, i % 5))) .collect(); dbg!(&scores); assert_eq!(8, *scores.iter().max().unwrap()); } }