2023 Day 23 Performance Improvements

This commit is contained in:
Burnus 2025-08-18 19:20:28 +02:00
parent 89f2b849ad
commit fef4a68522

View file

@ -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<Coordinate>,
slopes: HashSet<(Coordinate, Direction)>,
slopes: HashMap<Coordinate, Direction>,
start: Coordinate,
dest: Coordinate,
}
@ -61,17 +61,17 @@ impl<'a> TryFrom<&'a str> for Map {
fn try_from(value: &'a str) -> Result<Self, Self::Error> {
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<Vec<(usize, usize)>> {
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 {
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 {
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