Complete day 8 part 1

This commit is contained in:
Timothy Warren 2022-12-09 11:17:49 -05:00
parent fcae876701
commit 2916647f99

View File

@ -51,7 +51,7 @@ struct Grid<T> {
} }
impl<T> Grid<T> { impl<T> Grid<T> {
fn new(width: usize) -> Self { pub fn new(width: usize) -> Self {
Grid { Grid {
width, width,
vec: Vec::new(), vec: Vec::new(),
@ -59,16 +59,16 @@ impl<T> Grid<T> {
} }
// Convert x,y coordinate into linear array index // 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 (y * self.width) + x
} }
/// Convert linear array index to x,y coordinate /// 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) (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; let idx = row * self.width;
if idx < self.vec.len() { if idx < self.vec.len() {
@ -78,7 +78,7 @@ impl<T> Grid<T> {
} }
} }
fn row_last_idx(&self, row: usize) -> usize { pub fn row_last_idx(&self, row: usize) -> usize {
if (row + 1) > self.num_rows() { if (row + 1) > self.num_rows() {
return self.vec.len(); return self.vec.len();
} }
@ -86,32 +86,37 @@ impl<T> Grid<T> {
self.row_first_idx(row + 1) - 1 self.row_first_idx(row + 1) - 1
} }
fn num_rows(&self) -> usize { pub fn num_rows(&self) -> usize {
let even_rows = self.vec.len() / self.width; self.vec.len() / self.width
if self.vec.len() % self.width > 0 {
even_rows + 1
} else {
even_rows
}
} }
fn num_cols(&self) -> usize { pub fn num_cols(&self) -> usize {
self.width 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 start = self.row_first_idx(row_num);
let end = self.row_last_idx(row_num); let end = self.row_last_idx(row_num);
&mut self.vec[start..=end] &mut self.vec[start..=end]
} }
fn get_column_indexes(&self, col_num: usize) -> Vec<usize> { pub fn get_row_indexes(&self, row_num: usize) -> Vec<usize> {
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<usize> {
let mut indexes = Vec::new(); let mut indexes = Vec::new();
if col_num > self.num_cols() { if col_num >= self.num_cols() {
return indexes; panic!(
"Asked for column {}, there are {} columns",
col_num,
self.num_cols()
);
} }
for r in 0..self.num_rows() { for r in 0..self.num_rows() {
@ -124,9 +129,11 @@ impl<T> Grid<T> {
} }
impl Grid<Tree> { impl Grid<Tree> {
fn mark_outer_trees_visible(&mut self) { fn mark_outer_trees_visible(&mut self) -> &mut Self {
fn set_row_visible(row: &mut [Tree]) { 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 // Set top/bottom rows as visible
@ -137,25 +144,79 @@ impl Grid<Tree> {
self.get_column_indexes(0).into_iter().for_each(|id| { self.get_column_indexes(0).into_iter().for_each(|id| {
self.vec[id].set_all_visible(); self.vec[id].set_all_visible();
}); });
self.get_column_indexes(self.num_cols() - 1).into_iter().for_each(|id| { self.get_column_indexes(self.num_cols() - 1)
self.vec[id].set_all_visible(); .into_iter()
}); .for_each(|id| {
self.vec[id].set_all_visible();
});
self
} }
fn mark_visible_trees(&mut self) { fn mark_visible(&mut self, dir: VisibleDirection) -> &mut Self {
self.mark_outer_trees_visible(); let indexes: Vec<Vec<usize>> = 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 { pub fn get_visible_trees(&self) -> usize {
self self.vec
.vec
.iter() .iter()
.filter(|tree| tree.is_visible()) .filter(|tree| tree.is_visible())
.collect::<Vec<&Tree>>() .collect::<Vec<&Tree>>()
.len() .len()
} }
fn from_file_str(file_str: &'static str) -> Grid<Tree> { pub fn from_file_str(file_str: &'static str) -> Grid<Tree> {
let lines: Vec<&str> = file_str.lines().collect(); let lines: Vec<&str> = file_str.lines().collect();
let width = lines[0].len(); let width = lines[0].len();
let mut grid: Grid<Tree> = Grid::new(width); let mut grid: Grid<Tree> = Grid::new(width);
@ -182,7 +243,6 @@ fn main() {
let visible_num = grid.get_visible_trees(); let visible_num = grid.get_visible_trees();
println!("Part 1: Number of visible trees: {}", visible_num); println!("Part 1: Number of visible trees: {}", visible_num);
} }
#[cfg(test)] #[cfg(test)]
@ -193,6 +253,34 @@ mod tests {
include_str!("test-input.txt") 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] #[test]
fn test_outer_visible_trees() { fn test_outer_visible_trees() {
let mut grid = Grid::from_file_str(get_data()); let mut grid = Grid::from_file_str(get_data());
@ -200,4 +288,27 @@ mod tests {
assert_eq!(grid.get_visible_trees(), 16usize); 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);
}
} }