use crate::utils; use std::collections::HashSet; type Coord = i8; type Coords = ( Coord, Coord ); type Count = u16; type Height = u8; type Trails = Vec; 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 { s.to_string().parse::().ok() } struct Grid { items : Vec>> } 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 { 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::>() .len().try_into().expect("Answer should be <65K"); ( score, unique ) } else { ( 0, 0 ) } }, None => ( 0, 0 ), } } }