78 lines
1.9 KiB
Rust
78 lines
1.9 KiB
Rust
use std::io::BufRead;
|
|
|
|
#[derive(Debug, std::cmp::PartialEq)]
|
|
enum Cell {
|
|
Tree,
|
|
Empty
|
|
}
|
|
|
|
type Forest = Vec<Vec<Cell>>;
|
|
|
|
struct ForestSlopeIterator<'a> {
|
|
forest: &'a Forest,
|
|
horizontal_shift: usize,
|
|
vertical_shift: usize,
|
|
pos_x: usize,
|
|
pos_y: usize,
|
|
}
|
|
|
|
trait IterSlope {
|
|
fn iter_slope(&self, horizontal_shift: usize, vertical_shift: usize) -> ForestSlopeIterator;
|
|
}
|
|
|
|
impl IterSlope for Forest {
|
|
fn iter_slope(&self, horizontal_shift: usize, vertical_shift: usize) -> ForestSlopeIterator {
|
|
ForestSlopeIterator {
|
|
forest: self,
|
|
horizontal_shift,
|
|
vertical_shift,
|
|
pos_x: 0,
|
|
pos_y: 0,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> Iterator for ForestSlopeIterator<'a> {
|
|
type Item = &'a Cell;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
if self.pos_y >= self.forest.len() {
|
|
None
|
|
} else {
|
|
let cell = &self.forest[self.pos_y][self.pos_x];
|
|
self.pos_y += self.vertical_shift;
|
|
self.pos_x = (self.pos_x + self.horizontal_shift) % self.forest[0].len();
|
|
Some(cell)
|
|
}
|
|
}
|
|
}
|
|
|
|
fn challenge<F: BufRead> (input: F, slopes: &[(usize, usize)]) -> usize {
|
|
let forest: Forest = input.lines()
|
|
.map(
|
|
|line| line.unwrap().chars().map(
|
|
|c| match c {
|
|
'.' => Cell::Empty,
|
|
'#' => Cell::Tree,
|
|
_ => unreachable!()
|
|
}
|
|
).collect::<Vec<_>>()
|
|
)
|
|
.collect();
|
|
|
|
slopes.iter().map(
|
|
|(h_shift, v_shift)| forest.iter_slope(*h_shift, *v_shift)
|
|
.filter(|cell| **cell == Cell::Tree)
|
|
.count()
|
|
).fold(1, |acc, count| acc * count)
|
|
}
|
|
|
|
pub fn part1<F: BufRead> (input: F) {
|
|
println!("{}", challenge(input, &[(3, 1)]))
|
|
}
|
|
|
|
pub fn part2<F: BufRead> (input: F) {
|
|
let slopes = [(1, 1), (3, 1), (5, 1), (7, 1), (1, 2)];
|
|
println!("{}", challenge(input, &slopes))
|
|
}
|