Skip to content

Commit 725f9e2

Browse files
committed
Solved day 15 of 2021
1 parent e119e31 commit 725f9e2

File tree

4 files changed

+79
-37
lines changed

4 files changed

+79
-37
lines changed

2021/Cargo.toml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ rayon = "1.10.0"
1616
smallvec = "1"
1717

1818
[profile.release]
19-
strip = true
20-
lto = true
21-
panic = "abort"
22-
debug = "none"
19+
# strip = true
20+
# lto = true
21+
# panic = "abort"
22+
# debug = "none"
23+
debug = true

2022/src/bin/day12.rs

Lines changed: 13 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -34,37 +34,20 @@ impl From<u8> for Node {
3434
}
3535

3636
fn calculate_part1(grid: &Grid<Node>) -> usize {
37-
struct GraphPart1<'a> {
38-
grid: &'a Grid<Node>,
39-
}
40-
41-
impl SearchGraph for GraphPart1<'_> {
42-
type Node = Location;
43-
type Score = u32;
44-
45-
fn neighbours(&self, location: Location) -> impl Iterator<Item = (Location, u32)> {
46-
let current_height = self.grid.get(location).unwrap().height;
47-
Direction::ALL.into_iter().filter_map(move |dir| {
48-
let next = location + dir;
49-
let next_height = self.grid.get(next)?.height;
50-
if next_height - current_height <= 1 {
51-
Some((next, 1))
52-
} else {
53-
None
54-
}
55-
})
56-
}
57-
}
58-
59-
impl SearchGraphWithGoal for GraphPart1<'_> {
60-
fn is_goal(&self, location: Location) -> bool { self.grid.get(location).unwrap().c == b'E' }
61-
}
62-
6337
let start_node = grid.find(|height| height.c == b'S').expect("Find the starting node");
64-
a_star_search(&GraphPart1 { grid }, start_node)
65-
.expect("Expected a path from S to E")
66-
.len()
67-
- 1
38+
let end_node = grid.find(|height| height.c == b'E').expect("Find the ending node");
39+
let graph = grid.search_graph(
40+
end_node,
41+
|_, current, next| {
42+
if next.height - current.height <= 1 {
43+
Some(1)
44+
} else {
45+
None
46+
}
47+
},
48+
|_| 0,
49+
);
50+
a_star_search(&graph, start_node).expect("Expected a path from S to E").len() - 1
6851
}
6952

7053
fn calculate_part2(grid: &Grid<Node>) -> usize {

shared/src/grid.rs

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use nom::Err::Error;
1010
use nom::{AsBytes, AsChar, Compare, IResult, Input, Parser};
1111
use nom_parse_trait::ParseFrom;
1212
use std::fmt::{Debug, Formatter, Write};
13-
use std::ops::{Index, IndexMut, Range};
13+
use std::ops::{Add, Index, IndexMut, Range};
1414

1515
#[derive(Clone, Hash, PartialEq)]
1616
pub struct Grid<T> {
@@ -470,6 +470,20 @@ impl<T> Grid<T> {
470470
.save_with_format(filename, image::ImageFormat::Png)
471471
.expect("Expect saving to not be a problem");
472472
}
473+
474+
pub fn search_graph<'a, FS, FH, S>(
475+
&'a self,
476+
goal: Location,
477+
score_step: FS,
478+
heuristic_score: FH,
479+
) -> GridGraph<'a, T, FS, FH>
480+
where
481+
FS: Fn(Location, &T, &T) -> Option<S>,
482+
S: Copy + Default + Eq + Add<S, Output = S> + Ord,
483+
FH: Fn(Vector<2, i32>) -> S,
484+
{
485+
GridGraph::<'a, T, FS, FH> { grid: self, goal, score_step, heuristic_score }
486+
}
473487
}
474488

475489
impl<T: Copy + Into<char>> Debug for Grid<T> {
@@ -726,3 +740,41 @@ where
726740
#[inline]
727741
fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
728742
}
743+
744+
pub struct GridGraph<'a, T, FS, FH> {
745+
grid: &'a Grid<T>,
746+
goal: Location,
747+
score_step: FS,
748+
heuristic_score: FH,
749+
}
750+
751+
impl<'a, T, S, FS, FH> crate::search::SearchGraph for GridGraph<'a, T, FS, FH>
752+
where
753+
FS: Fn(Location, &T, &T) -> Option<S>,
754+
S: Copy + Default + Eq + Add<S, Output = S> + Ord,
755+
FH: Fn(Vector<2, i32>) -> S,
756+
{
757+
type Node = Location;
758+
type Score = S;
759+
760+
fn neighbours(&self, current_loc: Location) -> impl Iterator<Item = (Location, S)> {
761+
let current_val = self.grid.get(current_loc).unwrap();
762+
self.grid.direct_neighbours(current_loc).flat_map(move |(dir, val)| {
763+
let next_loc = current_loc + dir;
764+
(self.score_step)(next_loc, current_val, val).map(|score| (next_loc, score))
765+
})
766+
}
767+
768+
fn expected_state_size(&self) -> usize { (self.grid.width() * self.grid.height()) as usize }
769+
}
770+
771+
impl<'a, T, S, FS, FH> crate::search::SearchGraphWithGoal for GridGraph<'a, T, FS, FH>
772+
where
773+
FS: Fn(Location, &T, &T) -> Option<S>,
774+
S: Copy + Default + Eq + Add<S, Output = S> + Ord,
775+
FH: Fn(Vector<2, i32>) -> S,
776+
{
777+
fn is_goal(&self, curr: Location) -> bool { curr == self.goal }
778+
779+
fn heuristic(&self, curr: Location) -> Self::Score { (self.heuristic_score)(self.goal - curr) }
780+
}

shared/src/search.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ pub trait SearchGraph {
1111
type Score: Copy + Default + Eq + Add<Self::Score, Output = Self::Score> + Ord;
1212

1313
fn neighbours(&self, node: Self::Node) -> impl Iterator<Item = (Self::Node, Self::Score)>;
14+
15+
fn expected_state_size(&self) -> usize { 1000 }
1416
}
1517

1618
pub trait SearchGraphWithGoal: SearchGraph {
@@ -40,9 +42,13 @@ pub fn a_star_search<G: SearchGraphWithGoal>(
4042
graph: &G,
4143
start_node: G::Node,
4244
) -> Option<Vec<G::Node>> {
43-
let mut current_states = HashMap::with_capacity_and_hasher(1000, FxBuildHasher::default());
45+
let mut current_states =
46+
HashMap::with_capacity_and_hasher(graph.expected_state_size(), FxBuildHasher::default());
4447
current_states.insert(start_node, (G::Score::default(), None)); // the value is the score + where the node came from
45-
let mut open_set = PriorityQueue::with_capacity_and_hasher(1000, FxBuildHasher::default());
48+
let mut open_set = PriorityQueue::with_capacity_and_hasher(
49+
graph.expected_state_size(),
50+
FxBuildHasher::default(),
51+
);
4652
open_set.push(start_node, Reverse(G::Score::default())); // open_set uses the f_score as priority
4753

4854
while let Some((node, _)) = open_set.pop() {

0 commit comments

Comments
 (0)