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> {
|
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)
|
||||||
|
.into_iter()
|
||||||
|
.for_each(|id| {
|
||||||
self.vec[id].set_all_visible();
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user