diff --git a/src/main.rs b/src/main.rs index f7e52eb..3c28fb0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -30,7 +30,8 @@ fn main() -> Result<()> { 6 => AocDaySixSolution, 7 => AocDaySevenSolution, 8 => AocDayEightSolution, - 9 => AocDayNineSolution + 9 => AocDayNineSolution, + 10 => AocDayTenSolution, }; Ok(()) diff --git a/src/solutions/day_10.rs b/src/solutions/day_10.rs index a78b198..9fa47a1 100644 --- a/src/solutions/day_10.rs +++ b/src/solutions/day_10.rs @@ -1,8 +1,120 @@ -use std::{fs::read_to_string, path::Path}; +use std::{ + collections::{HashMap, HashSet}, + fs::read_to_string, + path::Path, +}; use super::AocSolution; -use crate::utils::Result; +use crate::utils::{coord::Coord as Crd, Result}; +type Coord = Crd; + +struct HikingMap { + pub starting_points: HashSet, + pub mountain: HashMap, +} + +impl HikingMap { + fn new(src: &str) -> Self { + let (starting_points, mountain) = src + .lines() + .zip(0..) + .flat_map(|(line, y)| { + line.chars().zip(0..).filter_map(move |(ch, x)| match ch { + '0' => Some((Coord::new(x, y), 0)), + '1' => Some((Coord::new(x, y), 1)), + '2' => Some((Coord::new(x, y), 2)), + '3' => Some((Coord::new(x, y), 3)), + '4' => Some((Coord::new(x, y), 4)), + '5' => Some((Coord::new(x, y), 5)), + '6' => Some((Coord::new(x, y), 6)), + '7' => Some((Coord::new(x, y), 7)), + '8' => Some((Coord::new(x, y), 8)), + '9' => Some((Coord::new(x, y), 9)), + _ => None, + }) + }) + .fold( + (HashSet::new(), HashMap::new()), + |(mut spos, mut map), (coord, heigh)| { + if heigh == 0 { + spos.insert(coord); + } + + map.insert(coord, heigh); + + (spos, map) + }, + ); + + Self { + starting_points, + mountain, + } + } + + fn hike(&self) -> u64 { + fn _inner(map: &HashMap, start_pos: Coord) -> u64 { + fn _traverse(map: &HashMap, summits: &mut HashSet, current: Coord) { + if map.get(¤t).is_some_and(|h| h == &9) { + summits.insert(current); + return; + } + + for dir in current.surround() { + if map.get(&dir).is_some_and(|&h| map[¤t] + 1 == h) { + _traverse(map, summits, dir); + } + } + } + + let mut visited = HashSet::new(); + if map.contains_key(&start_pos) { + _traverse(map, &mut visited, start_pos); + visited.len() as u64 + } else { + 0 + } + } + + self.starting_points + .iter() + .map(|pos| _inner(&self.mountain, *pos)) + .sum() + } + + fn hike_ver_two(&self) -> u64 { + fn _inner(map: &HashMap, start_pos: Coord) -> u64 { + fn _traverse(map: &HashMap, u8>, current: Coord, rate: &mut u64) { + if map.get(¤t).is_some_and(|h| h == &9) { + *rate += 1; + return; + } + + for dir in current.surround() { + if map.get(&dir).is_some_and(|&h| map[¤t] + 1 == h) { + _traverse(map, dir, rate); + } + } + } + + let mut rating = 0; + if map.contains_key(&start_pos) { + _traverse(map, start_pos, &mut rating); + rating + } else { + 0 + } + } + + self.starting_points + .iter() + .map(|pos| _inner(&self.mountain, *pos)) + .sum() + } +} + +#[derive(Clone, Copy)] pub struct AocDayTenSolution; impl AocSolution for AocDayTenSolution { @@ -11,15 +123,17 @@ impl AocSolution for AocDayTenSolution { fn get_input(&self, path: Option<&Path>) -> Result { Ok(match path { Some(p) => read_to_string(p)?, - None => read_to_string("./input/day_day_10.txt")?, + None => read_to_string("./input/day_10.txt")?, }) } fn part_one(&self, input: &str) -> Result { - todo!() + let map = HikingMap::new(input); + Ok(map.hike()) } fn part_two(&self, input: &str) -> Result { - todo!() + let map = HikingMap::new(input); + Ok(map.hike_ver_two()) } } diff --git a/src/utils/coord.rs b/src/utils/coord.rs index b2c5314..7398788 100644 --- a/src/utils/coord.rs +++ b/src/utils/coord.rs @@ -13,9 +13,20 @@ pub struct Coord { } impl Coord { + #[inline(always)] pub const fn new(x: U, y: U) -> Self { Self { x, y } } + + #[inline(always)] + pub fn surround(&self) -> [Self; 4] { + [ + Self::new(self.x - U::from(1), self.y), + Self::new(self.x, self.y + U::from(1)), + Self::new(self.x + U::from(1), self.y), + Self::new(self.x, self.y - U::from(1)), + ] + } } impl Add for Coord {