[TASK] Implemented Day 8
This commit is contained in:
201
src/day8.rs
Normal file
201
src/day8.rs
Normal file
@@ -0,0 +1,201 @@
|
||||
use std::{fmt::{Debug, Display}};
|
||||
|
||||
use crate::day_solver::DaySolver;
|
||||
|
||||
use super::util;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Grid<T> {
|
||||
width: usize,
|
||||
data: Vec<T>
|
||||
}
|
||||
|
||||
impl<T: Clone + Sized> Grid<T> {
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn set_row(&mut self, x: usize, v: T) {
|
||||
// let range = &mut self.data[x * self.width..(x+1) * self.width];
|
||||
for i in self.width * x..self.width * (x + 1) {
|
||||
self.data[i] = v.to_owned();
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn set_col(&mut self, x: usize, v: T) {
|
||||
for y in 0..self.height() {
|
||||
let idx = self.idx(&x, &y);
|
||||
self.data[idx] = v.to_owned();
|
||||
}
|
||||
}
|
||||
|
||||
fn idx(&self, x: &usize, y: &usize) -> usize {
|
||||
y * self.width + x
|
||||
}
|
||||
|
||||
fn height(&self) -> usize {
|
||||
self.data.len() / self.width
|
||||
}
|
||||
|
||||
fn get(&self, x: &usize, y: &usize) -> &T {
|
||||
let idx = self.idx(x, y);
|
||||
&self.data[idx]
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
impl <T: Display + Clone + Sized> Grid<T> {
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn print(&self) {
|
||||
|
||||
for y in 0..self.height() {
|
||||
for x in 0..self.width {
|
||||
print!("{}", self.get(&x, &y))
|
||||
}
|
||||
println!();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Day8 {
|
||||
grid: Grid<u8>
|
||||
}
|
||||
|
||||
impl Day8 {
|
||||
|
||||
pub fn create() -> Self {
|
||||
// let lines = util::read_file("input/day8_example.txt");
|
||||
let lines = util::read_file("input/day8.txt");
|
||||
|
||||
// Put the input into the day struct
|
||||
let grid = Grid {
|
||||
width: lines.first().unwrap().len(),
|
||||
data: lines.join("").chars().map(|c| c.to_digit(10).unwrap() as u8).collect()
|
||||
};
|
||||
// println!("{:?}", grid);
|
||||
return Day8 {
|
||||
grid
|
||||
}
|
||||
}
|
||||
|
||||
fn calc_required_heights_for_x_range<R>(&self, y: usize, required_heights: &mut Grid<u8>, range: R)
|
||||
where R: IntoIterator<Item = usize> {
|
||||
|
||||
let mut min_required_height = 0;
|
||||
for x in range {
|
||||
self.update_required_heights(x, y, required_heights, &mut min_required_height);
|
||||
if min_required_height >= 10 { break }
|
||||
}
|
||||
}
|
||||
|
||||
fn calc_required_heights_for_y_range<R>(&self, x: usize, required_heights: &mut Grid<u8>, range: R)
|
||||
where R: IntoIterator<Item = usize> {
|
||||
|
||||
let mut min_required_height = 0;
|
||||
for y in range {
|
||||
self.update_required_heights(x, y, required_heights, &mut min_required_height);
|
||||
if min_required_height >= 10 { break }
|
||||
}
|
||||
}
|
||||
|
||||
fn update_required_heights(&self, x: usize, y: usize, required_heights: &mut Grid<u8>, min_required_height: &mut u8) {
|
||||
let idx = self.grid.idx(&x, &y);
|
||||
if required_heights.data[idx] >= *min_required_height {
|
||||
required_heights.data[idx] = *min_required_height
|
||||
}
|
||||
let tree_height = self.grid.data[idx];
|
||||
if tree_height + 1 > *min_required_height {
|
||||
*min_required_height = tree_height + 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn calc_viewing_dist_x<R>(&self, cur_height: &u8, x_range: R, y: &usize) -> usize
|
||||
where R: IntoIterator<Item = usize> {
|
||||
|
||||
let mut count = 0;
|
||||
for x in x_range {
|
||||
count += 1;
|
||||
if self.grid.get(&x, &y) >= cur_height {
|
||||
break;
|
||||
}
|
||||
}
|
||||
count
|
||||
}
|
||||
|
||||
fn calc_viewing_dist_y<R>(&self, cur_height: &u8, x: &usize, y_range: R) -> usize
|
||||
where R: IntoIterator<Item = usize> {
|
||||
|
||||
let mut count = 0;
|
||||
for y in y_range {
|
||||
count += 1;
|
||||
if self.grid.get(&x, &y) >= &cur_height {
|
||||
break;
|
||||
}
|
||||
}
|
||||
count
|
||||
}
|
||||
}
|
||||
|
||||
impl DaySolver for Day8 {
|
||||
|
||||
|
||||
fn solve_part1(&mut self) -> String {
|
||||
let mut required_heights: Grid<u8> = Grid {
|
||||
width: self.grid.width,
|
||||
data: vec![10u8; self.grid.data.len()]
|
||||
};
|
||||
|
||||
// First, we go over the rows, scanning them left-to-right
|
||||
for y in 0..self.grid.height() {
|
||||
|
||||
self.calc_required_heights_for_x_range(y, &mut required_heights, 0..self.grid.width);
|
||||
// println!("After y = {} L2R", y);
|
||||
// required_heights.print();
|
||||
self.calc_required_heights_for_x_range(y, &mut required_heights, (0..self.grid.width).rev());
|
||||
// println!("After y = {} R2L", y);
|
||||
// required_heights.print();
|
||||
}
|
||||
|
||||
for x in 0..self.grid.width {
|
||||
|
||||
self.calc_required_heights_for_y_range(x, &mut required_heights, 0..self.grid.height());
|
||||
self.calc_required_heights_for_y_range(x, &mut required_heights, (0..self.grid.height()).rev());
|
||||
}
|
||||
|
||||
// required_heights.print();
|
||||
|
||||
let mut visible_trees = 0;
|
||||
for i in 0..required_heights.data.len() {
|
||||
if self.grid.data[i] >= required_heights.data[i] {
|
||||
visible_trees += 1;
|
||||
}
|
||||
}
|
||||
return visible_trees.to_string();
|
||||
}
|
||||
|
||||
fn solve_part2(&mut self) -> String {
|
||||
|
||||
// Note that we skip the edges; since one of the distances is 0, the scenic score will also be 0
|
||||
let mut max_scenic_score = 0;
|
||||
for y in 1..self.grid.height() - 1 {
|
||||
for x in 1..self.grid.width - 1 {
|
||||
|
||||
let cur_height = self.grid.get(&x, &y);
|
||||
let right_view = self.calc_viewing_dist_x(cur_height, x+1..self.grid.width, &y);
|
||||
let left_view = self.calc_viewing_dist_x(cur_height, (0..x).rev(), &y);
|
||||
let up_view = self.calc_viewing_dist_y(cur_height, &x, y + 1..self.grid.height());
|
||||
let down_view = self.calc_viewing_dist_y(cur_height, &x, (0..y).rev());
|
||||
|
||||
let scenic_score = left_view * right_view * up_view * down_view;
|
||||
if scenic_score > max_scenic_score {
|
||||
max_scenic_score = scenic_score;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return max_scenic_score.to_string();
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ use crate::day4::Day4;
|
||||
use crate::day5::Day5;
|
||||
use crate::day6::Day6;
|
||||
use crate::day7::Day7;
|
||||
use crate::day8::Day8;
|
||||
use crate::day_solver::DaySolver;
|
||||
|
||||
mod util;
|
||||
@@ -17,8 +18,9 @@ mod day4;
|
||||
mod day5;
|
||||
mod day6;
|
||||
mod day7;
|
||||
mod day8;
|
||||
|
||||
const MAX_DAY: u8 = 7;
|
||||
const MAX_DAY: u8 = 8;
|
||||
const DEFAULT_BENCHMARK_AMOUNT: u32 = 100;
|
||||
|
||||
fn main() {
|
||||
@@ -89,6 +91,7 @@ fn build_day_solver(day: u8) -> Option<Box<dyn DaySolver>> {
|
||||
5 => Some(Box::new(Day5::create())),
|
||||
6 => Some(Box::new(Day6::create())),
|
||||
7 => Some(Box::new(Day7::create())),
|
||||
8 => Some(Box::new(Day8::create())),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user