diff --git a/2022/Cargo.toml b/2022/Cargo.toml index 5e98067..f35ce18 100644 --- a/2022/Cargo.toml +++ b/2022/Cargo.toml @@ -35,6 +35,10 @@ path = "src/day6.rs" name = "day7" path = "src/day7.rs" +[[bin]] +name = "day8" +path = "src/day8.rs" + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] diff --git a/2022/src/day8.rs b/2022/src/day8.rs new file mode 100644 index 0000000..68eef8a --- /dev/null +++ b/2022/src/day8.rs @@ -0,0 +1,93 @@ +const DATA: &'static str = include_str!("../data/day8.txt"); +// const DATA: &'static str = " +// 30373 +// 25512 +// 65332 +// 33549 +// 35390 +// "; + + +// O(N * (2 * sqrt(N) - 1)), so roughly N^1.5? Where N is number of elements in the grid +fn is_visible(grid: &Vec>, x: usize, y: usize) -> bool { + let height = grid[y][x]; + let rows = grid.len(); + let cols = grid[x].len(); + // search horizontal + let vis_left = (0..x).all(|cmp_x| grid[y][cmp_x] < height); + let vis_right = ((x + 1)..cols).all(|cmp_x| grid[y][cmp_x] < height); + + let vis_top = (0..y).all(|cmp_y| grid[cmp_y][x] < height); + let vis_bottom = ((y + 1)..rows).all(|cmp_y| grid[cmp_y][x] < height); + + vis_left || vis_right || vis_top || vis_bottom +} + + +fn scenic_score(grid: &Vec>, x: usize, y: usize) -> usize { + let height = grid[y][x]; + let rows = grid.len(); + let cols = grid[x].len(); + + let sc_left = (0..x).rev() + .position(|cmp_x| grid[y][cmp_x] >= height) // 0-indexed position of the first blocking tree + .map(|p| p + 1) // +1 since we include the blocking tree in the count + .unwrap_or(x); // if no blocking trees, score is how many are to the left of current + + let sc_right = ((x + 1)..cols) + .position(|cmp_x| grid[y][cmp_x] >= height) + .map(|p| p + 1) + .unwrap_or(cols - x - 1); // e.g. if x is 4 and there are 5 cols, this is rightmost, so 5 - 4 - 1 = 0 + + let sc_top = (0..y).rev() + .position(|cmp_y| grid[cmp_y][x] >= height) + .map(|p| p + 1) + .unwrap_or(y); + + let sc_bottom = ((y + 1)..rows) + .position(|cmp_y| grid[cmp_y][x] >= height) + .map(|p| p + 1) + .unwrap_or(rows - y - 1); + + sc_left * sc_right * sc_top * sc_bottom +} + + +fn build_grid(data: &str) -> Result>, String> { + data.trim() + .lines() + .map(|line| { + line.chars() + .map(|c| c.to_digit(10).map(|c| c as usize).ok_or_else(|| format!("Failed to convert to integer: {c}") )) + .collect::, String>>() + }) + .collect::>, String>>() +} + + +fn main() -> Result<(), String> { + let grid = build_grid(DATA)?; + + let mut visible_trees = 0; + for y in 0..grid.len() { + for x in 0..grid[y].len() { + if is_visible(&grid, x, y) { + visible_trees += 1; + } + } + } + println!("Part 1: {visible_trees}"); + + let mut max_score = 0; + for y in 0..grid.len() { + for x in 0..grid[y].len() { + let score = scenic_score(&grid, x, y); + if score > max_score { + max_score = score; + } + } + } + println!("Part 2: {max_score}"); + + Ok(()) +}