From 2916647f99260f95be53a121755a370afc9fb8f2 Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Fri, 9 Dec 2022 11:17:49 -0500 Subject: [PATCH] Complete day 8 part 1 --- day8/src/main.rs | 169 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 140 insertions(+), 29 deletions(-) diff --git a/day8/src/main.rs b/day8/src/main.rs index 18e92da..6f7e601 100644 --- a/day8/src/main.rs +++ b/day8/src/main.rs @@ -51,7 +51,7 @@ struct Grid { } impl Grid { - fn new(width: usize) -> Self { + pub fn new(width: usize) -> Self { Grid { width, vec: Vec::new(), @@ -59,16 +59,16 @@ impl Grid { } // Convert x,y coordinate into linear array index - fn xy_idx(&self, x: usize, y: usize) -> usize { + pub fn xy_idx(&self, x: usize, y: usize) -> usize { (y * self.width) + x } /// Convert linear array index to x,y coordinate - fn idx_xy(&self, idx: usize) -> (usize, usize) { + pub fn idx_xy(&self, idx: usize) -> (usize, usize) { (idx % self.width, idx / self.width) } - fn row_first_idx(&self, row: usize) -> usize { + pub fn row_first_idx(&self, row: usize) -> usize { let idx = row * self.width; if idx < self.vec.len() { @@ -78,7 +78,7 @@ impl Grid { } } - fn row_last_idx(&self, row: usize) -> usize { + pub fn row_last_idx(&self, row: usize) -> usize { if (row + 1) > self.num_rows() { return self.vec.len(); } @@ -86,32 +86,37 @@ impl Grid { self.row_first_idx(row + 1) - 1 } - fn num_rows(&self) -> usize { - let even_rows = self.vec.len() / self.width; - - if self.vec.len() % self.width > 0 { - even_rows + 1 - } else { - even_rows - } + pub fn num_rows(&self) -> usize { + self.vec.len() / self.width } - fn num_cols(&self) -> usize { + pub fn num_cols(&self) -> usize { self.width } - fn get_row(&mut self, row_num: usize) -> &mut [T] { + pub fn get_row(&mut self, row_num: usize) -> &mut [T] { let start = self.row_first_idx(row_num); let end = self.row_last_idx(row_num); &mut self.vec[start..=end] } - fn get_column_indexes(&self, col_num: usize) -> Vec { + pub fn get_row_indexes(&self, row_num: usize) -> Vec { + let start = self.row_first_idx(row_num); + let end = self.row_last_idx(row_num); + + (start..=end).collect() + } + + pub fn get_column_indexes(&self, col_num: usize) -> Vec { let mut indexes = Vec::new(); - if col_num > self.num_cols() { - return indexes; + if col_num >= self.num_cols() { + panic!( + "Asked for column {}, there are {} columns", + col_num, + self.num_cols() + ); } for r in 0..self.num_rows() { @@ -124,9 +129,11 @@ impl Grid { } impl Grid { - fn mark_outer_trees_visible(&mut self) { + fn mark_outer_trees_visible(&mut self) -> &mut Self { fn set_row_visible(row: &mut [Tree]) { - row.iter_mut().for_each(|tree| { tree.set_all_visible(); }) + row.iter_mut().for_each(|tree| { + tree.set_all_visible(); + }) } // Set top/bottom rows as visible @@ -137,25 +144,79 @@ impl Grid { self.get_column_indexes(0).into_iter().for_each(|id| { self.vec[id].set_all_visible(); }); - self.get_column_indexes(self.num_cols() - 1).into_iter().for_each(|id| { - self.vec[id].set_all_visible(); - }); + self.get_column_indexes(self.num_cols() - 1) + .into_iter() + .for_each(|id| { + self.vec[id].set_all_visible(); + }); + + self } - fn mark_visible_trees(&mut self) { - self.mark_outer_trees_visible(); + fn mark_visible(&mut self, dir: VisibleDirection) -> &mut Self { + let indexes: Vec> = match dir { + Top | Bottom => { + // Skip outer columns, as those are already marked visible + (1..(self.num_cols() - 1)) + .map(|c| self.get_column_indexes(c)) + .map(|column| { + if dir == Bottom { + column.into_iter().rev().collect() + } else { + column + } + }) + .collect() + } + Left | Right => { + // Skip first and last rows, as those are already marked visible + (1..(self.num_rows() - 1)) + .map(|r| self.get_row_indexes(r)) + .map(|row| { + if dir == Right { + row.into_iter().rev().collect() + } else { + row + } + }) + .collect() + } + }; + + for row_or_col in indexes { + let mut tallest = 0usize; + + for idx in row_or_col { + let tree = &mut self.vec[idx]; + + if tallest < tree.height { + tree.set_visible(dir); + + tallest = tree.height; + } + } + } + + self + } + + pub fn mark_visible_trees(&mut self) { + self.mark_outer_trees_visible() + .mark_visible(Top) + .mark_visible(Right) + .mark_visible(Bottom) + .mark_visible(Left); } pub fn get_visible_trees(&self) -> usize { - self - .vec + self.vec .iter() .filter(|tree| tree.is_visible()) .collect::>() .len() } - fn from_file_str(file_str: &'static str) -> Grid { + pub fn from_file_str(file_str: &'static str) -> Grid { let lines: Vec<&str> = file_str.lines().collect(); let width = lines[0].len(); let mut grid: Grid = Grid::new(width); @@ -182,7 +243,6 @@ fn main() { let visible_num = grid.get_visible_trees(); println!("Part 1: Number of visible trees: {}", visible_num); - } #[cfg(test)] @@ -193,6 +253,34 @@ mod tests { include_str!("test-input.txt") } + #[test] + fn test_row_first_index() { + let grid = Grid::from_file_str(get_data()); + + assert_eq!(grid.row_first_idx(1), 5); + assert_eq!(grid.row_first_idx(0), 0); + assert_eq!(grid.row_first_idx(2), 10); + } + + #[test] + fn test_row_last_index() { + let grid = Grid::from_file_str(get_data()); + + assert_eq!(grid.row_last_idx(0), 4); + assert_eq!(grid.row_last_idx(1), 9); + } + + #[test] + fn test_get_column_indexes() { + let mut grid = Grid::from_file_str(get_data()); + + assert_eq!(grid.width, 5); + + assert_eq!(grid.get_column_indexes(0), vec![0, 5, 10, 15, 20]); + assert_eq!(grid.get_column_indexes(1), vec![1, 6, 11, 16, 21]); + assert_eq!(grid.get_column_indexes(4), vec![4, 9, 14, 19, 24]); + } + #[test] fn test_outer_visible_trees() { let mut grid = Grid::from_file_str(get_data()); @@ -200,4 +288,27 @@ mod tests { assert_eq!(grid.get_visible_trees(), 16usize); } + + #[test] + fn test_visible_trees() { + let mut grid = Grid::from_file_str(get_data()); + grid.mark_visible_trees(); + + let visible = [(1usize, 1usize), (2, 1), (1, 2), (4, 3), (2, 3)]; + + for (x, y) in visible { + let idx = grid.xy_idx(x, y); + + assert!( + grid.vec[idx].is_visible(), + "Tree {}({},{}) should be visible: {:#?}", + idx, + x, + y, + grid.vec[idx] + ); + } + + assert_eq!(grid.get_visible_trees(), 21usize); + } }