diff --git a/2023/day23_a_long_walk/src/lib.rs b/2023/day23_a_long_walk/src/lib.rs index 398af1c..4cbd68e 100644 --- a/2023/day23_a_long_walk/src/lib.rs +++ b/2023/day23_a_long_walk/src/lib.rs @@ -1,5 +1,5 @@ use core::fmt::Display; -use std::{num::ParseIntError, collections::HashSet}; +use std::{num::ParseIntError, collections::HashSet, collections::HashMap}; #[derive(Debug, PartialEq, Eq)] pub enum ParseError<'a> { @@ -32,7 +32,7 @@ impl Display for ParseError<'_> { } } -#[derive(PartialEq, Eq, Hash, Clone, Copy)] +#[derive(PartialEq, Eq, Hash, Clone, Copy, PartialOrd, Ord)] struct Coordinate(usize, usize); #[derive(PartialEq, Eq, Hash)] @@ -51,7 +51,7 @@ impl Direction { struct Map{ path: HashSet, - slopes: HashSet<(Coordinate, Direction)>, + slopes: HashMap, start: Coordinate, dest: Coordinate, } @@ -61,17 +61,17 @@ impl<'a> TryFrom<&'a str> for Map { fn try_from(value: &'a str) -> Result { let mut path = HashSet::new(); - let mut slopes = HashSet::new(); + let mut slopes = HashMap::new(); for (y, line) in value.lines().enumerate() { for (x, c) in line.chars().enumerate() { match c { '#' => (), '.' => _ = path.insert(Coordinate(x, y)), - '^' => _ = slopes.insert((Coordinate(x, y), Direction::North)), - '<' => _ = slopes.insert((Coordinate(x, y), Direction::East)), - '>' => _ = slopes.insert((Coordinate(x, y), Direction::West)), - 'v' => _ = slopes.insert((Coordinate(x, y), Direction::South)), + '^' => _ = slopes.insert(Coordinate(x, y), Direction::North), + '<' => _ = slopes.insert(Coordinate(x, y), Direction::East), + '>' => _ = slopes.insert(Coordinate(x, y), Direction::West), + 'v' => _ = slopes.insert(Coordinate(x, y), Direction::South), e => return Err(Self::Error::InvalidChar(e)), } } @@ -98,21 +98,24 @@ impl<'a> TryFrom<&'a str> for Map { impl Map { fn distances(&self, steep_slopes: bool) -> Vec> { - let mut res = Vec::new(); let mut nodes = vec![self.start, self.dest]; self.path.iter().filter(|n| self.neighbours(**n).len() > 2).for_each(|n| nodes.push(*n)); - self.slopes.iter().for_each(|s| nodes.push(s.0)); + self.slopes.keys().for_each(|pos| nodes.push(*pos)); + nodes.sort(); + let mut res = Vec::with_capacity(nodes.len()); nodes.iter().for_each(|from_node| { let mut this = Vec::new(); self.neighbours(*from_node).iter().for_each(|&n| { - let slope = self.slopes.iter().find(|(pos, _dir)| pos == from_node); - if !steep_slopes || slope.is_none() || slope.unwrap().1.is_direction(*from_node, n) { + if !steep_slopes || { + let dir = self.slopes.get(from_node); + dir.is_none() || dir.unwrap().is_direction(*from_node, n) + } { let mut prev = *from_node; let mut curr = n; let mut len = 1; loop { - if let Some(to_idx) = nodes.iter().position(|n| n == &curr) { + if let Ok(to_idx) = nodes.binary_search(&curr) { this.push((to_idx, len)); break; } @@ -134,17 +137,13 @@ impl Map { let right_idx = middle[1].0; let d = middle[0].1 + middle[1].1; res[idx] = Vec::new(); - res[left_idx].iter_mut().for_each(|(dest, len)| { - if *dest == idx { - *dest = right_idx; - *len = d; - } + res[left_idx].iter_mut().filter(|(dest, _len)| *dest == idx).for_each(|(dest, len)| { + *dest = right_idx; + *len = d; }); - res[right_idx].iter_mut().for_each(|(dest, len)| { - if *dest == idx { - *dest = left_idx; - *len = d; - } + res[right_idx].iter_mut().filter(|(dest, _len)| *dest == idx).for_each(|(dest, len)| { + *dest = left_idx; + *len = d; }); } res @@ -158,10 +157,10 @@ impl Map { if self.path.contains(&Coordinate(pos.0+1, pos.1)) { res.push(Coordinate(pos.0+1, pos.1)); } if self.path.contains(&Coordinate(pos.0, pos.1+1)) { res.push(Coordinate(pos.0, pos.1+1)); } - if pos.0 > 0 && self.slopes.iter().any(|(p, _)| p == &Coordinate(pos.0-1, pos.1)) { res.push(Coordinate(pos.0-1, pos.1)); } - if pos.1 > 0 && self.slopes.iter().any(|(p, _)| p == &Coordinate(pos.0, pos.1-1)) { res.push(Coordinate(pos.0, pos.1-1)); } - if self.slopes.iter().any(|(p, _)| p == &Coordinate(pos.0+1, pos.1)) { res.push(Coordinate(pos.0+1, pos.1)); } - if self.slopes.iter().any(|(p, _)| p == &Coordinate(pos.0, pos.1+1)) { res.push(Coordinate(pos.0, pos.1+1)); } + if pos.0 > 0 && self.slopes.contains_key(&Coordinate(pos.0-1, pos.1)) { res.push(Coordinate(pos.0-1, pos.1)); } + if pos.1 > 0 && self.slopes.contains_key(&Coordinate(pos.0, pos.1-1)) { res.push(Coordinate(pos.0, pos.1-1)); } + if self.slopes.contains_key(&Coordinate(pos.0+1, pos.1)) { res.push(Coordinate(pos.0+1, pos.1)); } + if self.slopes.contains_key(&Coordinate(pos.0, pos.1+1)) { res.push(Coordinate(pos.0, pos.1+1)); } res } @@ -189,9 +188,7 @@ fn longest_route(distances: &[Vec<(usize, usize)>]) -> usize { continue; } distances[curr].iter().filter(|(n, _)| !path.contains(n)).for_each(|(next, _len)| { - let mut new = path.to_vec(); - new.push(*next); - open_set.push(new); + open_set.push(path.iter().cloned().chain(std::iter::once(*next)).collect()); }); } longest_so_far