2023 Day 23 Performance Improvements
This commit is contained in:
parent
89f2b849ad
commit
fef4a68522
1 changed files with 27 additions and 30 deletions
|
@ -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 {
|
||||
*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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue