Day 10
This commit is contained in:
parent
3b3a11bf7f
commit
17b62f7e79
|
@ -0,0 +1,109 @@
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
|
pub fn day10() {
|
||||||
|
let map = HikingMap::from_str(&crate::input(10));
|
||||||
|
|
||||||
|
let all_positions = (0..map.width()).cartesian_product(0..map.height());
|
||||||
|
let (scores, ratings) = all_positions
|
||||||
|
// only the 0s (trailheads)
|
||||||
|
.filter(|(x, y)| map.height_at(*x, *y) == 0)
|
||||||
|
// (score, rating) for each trailhead
|
||||||
|
.map(|(x, y)| find_trails(&map, x, y))
|
||||||
|
// (sum of scores, sum of ratings)
|
||||||
|
.fold((0, 0), |acc, e| (acc.0 + e.0, acc.1 + e.1));
|
||||||
|
|
||||||
|
println!("Sum of Trailhead Scores: {}", scores);
|
||||||
|
println!("Sum of Trailhead Ratings: {}", ratings);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_trails(map: &HikingMap, x: usize, y: usize) -> (usize, usize) {
|
||||||
|
fn find_trails(
|
||||||
|
map: &HikingMap,
|
||||||
|
x: usize,
|
||||||
|
y: usize,
|
||||||
|
visited: &mut Vec<(usize, usize)>,
|
||||||
|
) -> (usize, usize) {
|
||||||
|
if map.height_at(x, y) == 9 {
|
||||||
|
let score = if !visited.contains(&(x, y)) { 1 } else { 0 };
|
||||||
|
visited.push((x, y));
|
||||||
|
return (score, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Direction::all_variants()
|
||||||
|
.into_iter()
|
||||||
|
// all (nx, ny) that are accessible from (x, y)
|
||||||
|
.filter_map(|direction| map.travel(x, y, direction))
|
||||||
|
// each sum of (scores, ratings) for each adjacent position
|
||||||
|
.map(|(nx, ny)| find_trails(map, nx, ny, visited))
|
||||||
|
// sum of (scores, ratings) for this position's adjacent positions
|
||||||
|
.fold((0, 0), |acc, e| (acc.0 + e.0, acc.1 + e.1))
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut visited = vec![];
|
||||||
|
find_trails(map, x, y, &mut visited)
|
||||||
|
}
|
||||||
|
|
||||||
|
struct HikingMap {
|
||||||
|
map: Vec<Vec<u8>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HikingMap {
|
||||||
|
fn from_str(s: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
map: s
|
||||||
|
.lines()
|
||||||
|
.map(|line| {
|
||||||
|
line.chars()
|
||||||
|
.map(|c| c.to_digit(10).unwrap() as u8)
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn travel(&self, x: usize, y: usize, direction: Direction) -> Option<(usize, usize)> {
|
||||||
|
let (nx, ny) = direction.next_position(x, y)?;
|
||||||
|
|
||||||
|
// valid positions are in-bounds and moving upwards gradually
|
||||||
|
let is_valid = nx < self.width()
|
||||||
|
&& ny < self.height()
|
||||||
|
&& self.height_at(nx, ny).checked_sub(self.height_at(x, y)) == Some(1);
|
||||||
|
|
||||||
|
is_valid.then_some((nx, ny))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn height_at(&self, x: usize, y: usize) -> u8 {
|
||||||
|
self.map[y][x]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn height(&self) -> usize {
|
||||||
|
self.map.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn width(&self) -> usize {
|
||||||
|
self.map[0].len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
enum Direction {
|
||||||
|
North,
|
||||||
|
East,
|
||||||
|
South,
|
||||||
|
West,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Direction {
|
||||||
|
fn all_variants() -> Vec<Direction> {
|
||||||
|
vec![Self::North, Self::East, Self::South, Self::West]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_position(&self, x: usize, y: usize) -> Option<(usize, usize)> {
|
||||||
|
match self {
|
||||||
|
Self::North => Some((x, y.checked_sub(1)?)),
|
||||||
|
Self::East => Some((x.checked_add(1)?, y)),
|
||||||
|
Self::South => Some((x, y.checked_add(1)?)),
|
||||||
|
Self::West => Some((x.checked_sub(1)?, y)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,10 +14,12 @@ mod day6;
|
||||||
mod day7;
|
mod day7;
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
mod day8;
|
mod day8;
|
||||||
|
#[allow(dead_code)]
|
||||||
mod day9;
|
mod day9;
|
||||||
|
mod day10;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
day9::day9();
|
day10::day10();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn input(day: u8) -> String {
|
pub fn input(day: u8) -> String {
|
||||||
|
|
Loading…
Reference in New Issue