aoc-2024/src/day_10/mod.rs

105 lines
3.2 KiB
Rust

use crate::utils;
use std::collections::HashSet;
type Coord = i8;
type Coords = ( Coord, Coord );
type Count = u16;
type Height = u8;
type Trails = Vec<Coords>;
pub fn answer(text : String) -> ( Count, Count ) {
let grid : Grid = Grid::from(text);
let ( mut p1, mut p2 ) : ( Count, Count ) = ( 0, 0 );
for (y, line) in grid.items.iter().enumerate() {
for (x, _) in line.iter().enumerate() {
let ( score, unique ) = grid.trail_maps_from(&(x as Coord), &(y as Coord));
p1 = p1 + unique;
p2 = p2 + score;
}
}
( p1, p2 )
}
fn char_to_height(s : char) -> Option<Height> {
s.to_string().parse::<Height>().ok()
}
struct Grid {
items : Vec<Vec<Option<Height>>>
}
impl Grid {
fn all_neighbours_of_height(&self, height : Height, nodes : Trails) -> Trails {
nodes.iter()
.flat_map(|(x, y)| self.neighbours_of_height(height, *x, *y))
.collect()
}
fn from(s : String) -> Grid {
Grid {
items : s.split("\n")
.map(|line| line.chars().map(char_to_height).collect())
.collect()
}
}
fn get(&self, x : &Coord, y : &Coord) -> Option<Height> {
if *x < 0 || *y < 0 {
None
} else {
self.items
.get(*y as usize)
.and_then(|line| line.get(*x as usize))
.and_then(|a| *a)
}
}
fn neighbours_of_height(&self, height : Height, x : Coord, y : Coord) -> Vec<(Coord, Coord)> {
let mut v = Vec::new();
let offsets : [ (Coord, Coord); 4 ] = [
( x - 1, y ), ( x + 1, y ), ( x, y - 1 ), ( x, y + 1 )
];
for ( x, y ) in offsets.iter() {
if let Some(h) = self.get(&x, &y) {
if h == height {
v.push(( *x, *y ));
}
}
}
v
}
fn trail_maps_from(&self, x : &Coord, y : &Coord) -> ( Count, Count ) {
match self.get(x, y) {
Some(h) => {
if h == 0 {
let h0 : Trails = Vec::from([ (*x, *y) ]);
let h1 : Trails = self.all_neighbours_of_height(1, h0);
let h2 : Trails = self.all_neighbours_of_height(2, h1);
let h3 : Trails = self.all_neighbours_of_height(3, h2);
let h4 : Trails = self.all_neighbours_of_height(4, h3);
let h5 : Trails = self.all_neighbours_of_height(5, h4);
let h6 : Trails = self.all_neighbours_of_height(6, h5);
let h7 : Trails = self.all_neighbours_of_height(7, h6);
let h8 : Trails = self.all_neighbours_of_height(8, h7);
let h9 : Trails = self.all_neighbours_of_height(9, h8);
let score : Count = h9.len()
.try_into().expect("Answer should be <65K");
let unique : Count = h9.iter().collect::<HashSet<_>>()
.len().try_into().expect("Answer should be <65K");
( score, unique )
} else {
( 0, 0 )
}
},
None => ( 0, 0 ),
}
}
}