Complete day 8 part 1
This commit is contained in:
parent
fcae876701
commit
2916647f99
165
day8/src/main.rs
165
day8/src/main.rs
@ -51,7 +51,7 @@ struct Grid<T> {
|
||||
}
|
||||
|
||||
impl<T> Grid<T> {
|
||||
fn new(width: usize) -> Self {
|
||||
pub fn new(width: usize) -> Self {
|
||||
Grid {
|
||||
width,
|
||||
vec: Vec::new(),
|
||||
@ -59,16 +59,16 @@ impl<T> Grid<T> {
|
||||
}
|
||||
|
||||
// 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<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() {
|
||||
return self.vec.len();
|
||||
}
|
||||
@ -86,32 +86,37 @@ impl<T> Grid<T> {
|
||||
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<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();
|
||||
|
||||
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<T> Grid<T> {
|
||||
}
|
||||
|
||||
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]) {
|
||||
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<Tree> {
|
||||
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.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<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 {
|
||||
self
|
||||
.vec
|
||||
self.vec
|
||||
.iter()
|
||||
.filter(|tree| tree.is_visible())
|
||||
.collect::<Vec<&Tree>>()
|
||||
.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 width = lines[0].len();
|
||||
let mut grid: Grid<Tree> = 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);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user