You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
161 lines
2.9 KiB
Rust
161 lines
2.9 KiB
Rust
use crate::util::prelude::*;
|
|
|
|
static INPUT: &str = include_str!("inputs/day8.txt");
|
|
|
|
struct Trees {
|
|
width: usize,
|
|
height: usize,
|
|
data: Vec<sint>,
|
|
}
|
|
impl Trees {
|
|
fn from_str(s: &str) -> Self {
|
|
let mut lines = s.split('\n').filter(|s| !s.is_empty());
|
|
|
|
let mut width = 0;
|
|
let mut height = 0;
|
|
let mut data = Vec::new();
|
|
for line in lines {
|
|
for ch in line.chars() {
|
|
let h = ch as sint - '0' as sint;
|
|
data.push(h);
|
|
}
|
|
height += 1;
|
|
width = line.len();
|
|
}
|
|
|
|
Self {
|
|
width,
|
|
height,
|
|
data,
|
|
}
|
|
}
|
|
|
|
fn get(&self, x: usize, y: usize) -> sint {
|
|
self.data[x + y * self.width]
|
|
}
|
|
|
|
fn it<'a>(
|
|
&'a self,
|
|
start: (usize, usize),
|
|
next: impl Fn(&mut (usize, usize)) + 'a,
|
|
) -> impl Iterator<Item = sint> + 'a {
|
|
let mut n = Some(start);
|
|
|
|
core::iter::from_fn(move || {
|
|
let n_ = match &mut n {
|
|
None => return None,
|
|
Some(n) => n,
|
|
};
|
|
let r = Some(self.get(n_.0, n_.1));
|
|
|
|
if n_.0 == 0
|
|
|| n_.1 == 0 || n_.0 == self.width - 1
|
|
|| n_.1 == self.height - 1
|
|
{
|
|
n = None;
|
|
} else {
|
|
next(n_);
|
|
}
|
|
|
|
r
|
|
})
|
|
}
|
|
|
|
fn is_visible_(
|
|
&self,
|
|
x: usize,
|
|
y: usize,
|
|
next: impl Fn(&mut (usize, usize)),
|
|
) -> bool {
|
|
let h = self.get(x, y);
|
|
|
|
let t = self.it((x, y), next).skip(1).all(|h_| h_ < h);
|
|
|
|
t
|
|
}
|
|
|
|
fn is_visible(&self, x: usize, y: usize) -> bool {
|
|
let visible_left = self.is_visible_(x, y, |(x, _)| *x -= 1);
|
|
if visible_left {
|
|
return true;
|
|
}
|
|
|
|
let visible_right = self.is_visible_(x, y, |(x, _)| *x += 1);
|
|
if visible_right {
|
|
return true;
|
|
}
|
|
|
|
let visible_up = self.is_visible_(x, y, |(_, y)| *y -= 1);
|
|
if visible_up {
|
|
return true;
|
|
}
|
|
|
|
let visible_down = self.is_visible_(x, y, |(_, y)| *y += 1);
|
|
visible_down
|
|
}
|
|
|
|
fn scenic_score_(
|
|
&self,
|
|
x: usize,
|
|
y: usize,
|
|
v: uint,
|
|
next: impl Fn(&mut (usize, usize)),
|
|
) -> uint {
|
|
let it = self.it((x, y), next);
|
|
let h = self.get(x, y);
|
|
|
|
it.enumerate()
|
|
.skip(1)
|
|
.find(|(_, h_)| *h_ >= h)
|
|
.map(|(i, _)| i as uint)
|
|
.unwrap_or(v)
|
|
}
|
|
|
|
fn scenic_score(&self, x: usize, y: usize) -> uint {
|
|
let scenic_left = self.scenic_score_(x, y, x as uint, |(x, _)| *x -= 1);
|
|
let scenic_right =
|
|
self.scenic_score_(x, y, (self.width - x) as uint - 1, |(x, _)| {
|
|
*x += 1
|
|
});
|
|
let scenic_up = self.scenic_score_(x, y, y as uint, |(_, y)| *y -= 1);
|
|
let scenic_down = self.scenic_score_(
|
|
x,
|
|
y,
|
|
(self.height - y) as uint - 1,
|
|
|(_, y)| *y += 1,
|
|
);
|
|
|
|
scenic_left * scenic_right * scenic_up * scenic_down
|
|
}
|
|
}
|
|
|
|
pub fn part1() {
|
|
let trees = Trees::from_str(INPUT);
|
|
let trees_ = &trees;
|
|
|
|
println!(
|
|
"{}",
|
|
(0..trees.height)
|
|
.flat_map(
|
|
|y| (0..trees_.width).map(move |x| trees_.is_visible(x, y))
|
|
)
|
|
.filter(|x| *x)
|
|
.count()
|
|
);
|
|
}
|
|
|
|
pub fn part2() {
|
|
let trees = Trees::from_str(INPUT);
|
|
let trees_ = &trees;
|
|
|
|
println!(
|
|
"{}",
|
|
(0..trees.height)
|
|
.flat_map(
|
|
|y| (0..trees_.width).map(move |x| trees_.scenic_score(x, y))
|
|
)
|
|
.max()
|
|
.unwrap()
|
|
);
|
|
}
|