Skip to content

Commit f41ddb1

Browse files
committed
refactor: make is_end as function argument instead of struct property
1 parent 0754988 commit f41ddb1

File tree

4 files changed

+34
-46
lines changed

4 files changed

+34
-46
lines changed

src/solutions/year2023/day17.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,14 @@ impl Day17 {
6868
let cost = move |_, next: Node| {
6969
*grid_clone.get_for_point(&next.vector.position()).unwrap() as usize
7070
};
71-
let dijkstra: Dijkstra<Node> = Dijkstra::new(adjacency, Box::new(cost), Box::new(is_end));
71+
let dijkstra: Dijkstra<Node> = Dijkstra::new(adjacency, Box::new(cost));
7272

7373
let starts = vec![
7474
Node::new(start_point, Direction::East),
7575
Node::new(start_point, Direction::South),
7676
];
7777

78-
dijkstra.cost(starts).unwrap().to_string()
78+
dijkstra.cost(starts, &is_end).unwrap().to_string()
7979
}
8080

8181
fn filter_out_outside_grid(vec: Vec<Node>, grid: &Grid<u8>) -> Vec<Node> {

src/solutions/year2024/day16.rs

+8-7
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,19 @@ pub struct Day16;
1111
impl Solution for Day16 {
1212
fn part_one(&self, input: &str) -> String {
1313
let (grid, start, end) = Self::setup_grid(input);
14-
let dijkstra = Self::create_dijkstra(grid, end);
14+
let dijkstra = Self::create_dijkstra(grid);
15+
let is_end = Self::is_end_closure(end);
1516

16-
dijkstra.cost(vec![start]).unwrap().to_string()
17+
dijkstra.cost(vec![start], &is_end).unwrap().to_string()
1718
}
1819

1920
fn part_two(&self, input: &str) -> String {
2021
let (grid, start, end) = Self::setup_grid(input);
21-
let dijkstra = Self::create_dijkstra(grid, end);
22+
let dijkstra = Self::create_dijkstra(grid);
23+
let is_end = Self::is_end_closure(end);
2224

2325
dijkstra
24-
.all_paths(vec![start])
26+
.all_paths(vec![start], &is_end)
2527
.iter()
2628
.flat_map(|path| path.iter().map(|p| p.position()))
2729
.unique()
@@ -40,12 +42,11 @@ impl Day16 {
4042
(grid, start, end)
4143
}
4244

43-
fn create_dijkstra(grid: Grid<char>, end: Point) -> Dijkstra<Vector> {
45+
fn create_dijkstra(grid: Grid<char>) -> Dijkstra<Vector> {
4446
let adjacency = Self::adjacency_closure(grid);
4547
let cost = Self::cost_closure();
46-
let is_end = Self::is_end_closure(end);
4748

48-
Dijkstra::new(adjacency, cost, is_end)
49+
Dijkstra::new(adjacency, cost)
4950
}
5051

5152
fn adjacency_closure(grid: Grid<char>) -> Box<dyn Fn(Vector) -> Vec<Vector>> {

src/solutions/year2024/day21.rs

+16-20
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::solutions::year2024::day21::Key::{Activate, Dir};
22
use crate::solutions::Solution;
33
use crate::utils::direction::Direction;
4-
use crate::utils::graphs::a_star::AStarBuilder;
4+
use crate::utils::graphs::dijkstra::Dijkstra;
55
use crate::utils::grid::Grid;
66
use crate::utils::point::Point;
77
use itertools::Itertools;
@@ -53,38 +53,38 @@ impl Day21 {
5353
let path = self.path_for_str(&current, pad);
5454

5555
current = path.iter().map(|key| key.to_string()).collect::<String>();
56-
57-
// println!("{}", current);
5856
}
5957

6058
current.chars().count()
6159
}
6260

6361
fn path_for_str(&self, code: &str, pad: &Pad) -> Vec<Key> {
6462
let code = "A".to_owned() + code;
63+
let adjacent = pad.adjacent.clone();
6564

66-
let neighbours = |p: Point| pad.adjacent(&p);
67-
let distance = |_, _| 1;
65+
let neighbours = Box::new(move |p: Point| adjacent.get(&p).unwrap().to_vec());
66+
let distance = Box::new(|_, _| 1);
6867

69-
let a_star = AStarBuilder::init(&neighbours, &distance).build();
68+
let dijkstra = Dijkstra::new(neighbours, distance);
7069

7170
code.chars()
7271
.tuple_windows()
7372
.flat_map(|(from, to)| {
74-
let path = a_star
75-
.path(
76-
pad.position(from as u8).unwrap(),
77-
pad.position(to as u8).unwrap(),
78-
)
79-
.unwrap();
80-
let mut directions: Vec<Key> = path
73+
let start = pad.position(from as u8).unwrap();
74+
let end = pad.position(to as u8).unwrap();
75+
76+
let is_end = |p: Point| p == end;
77+
let path = dijkstra.all_paths(vec![start], &is_end);
78+
79+
let min_path = path.iter().min_by_key(|p| p.len()).unwrap();
80+
let mut directions: Vec<Key> = min_path
81+
.iter()
82+
.collect_vec()
8183
.windows(2)
82-
.map(|pair| Dir(pair[0].direction(&pair[1]).unwrap()))
84+
.map(|pair| Dir(pair[0].direction(pair[1]).unwrap()))
8385
.collect();
8486
directions.push(Activate);
8587

86-
// println!("{from} {to} -> {:?}", directions.iter().map(|d| d.to_string()).collect::<String>());
87-
8888
directions.into_iter()
8989
})
9090
.collect()
@@ -171,10 +171,6 @@ impl Pad {
171171
fn position(&self, element: u8) -> Option<Point> {
172172
self.positions.get(&element).copied()
173173
}
174-
175-
fn adjacent(&self, position: &Point) -> Vec<Point> {
176-
self.adjacent.get(position).unwrap().to_vec()
177-
}
178174
}
179175

180176
#[cfg(test)]

src/utils/graphs/dijkstra.rs

+8-17
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,14 @@ use std::hash::Hash;
77
pub struct Dijkstra<T> {
88
neighbours: Box<dyn Fn(T) -> Vec<T>>,
99
cost: Box<dyn Fn(T, T) -> usize>,
10-
is_end: Box<dyn Fn(T) -> bool>,
1110
}
1211

1312
impl<T> Dijkstra<T> {
14-
pub fn new(
15-
neighbours: Box<dyn Fn(T) -> Vec<T>>,
16-
cost: Box<dyn Fn(T, T) -> usize>,
17-
is_end: Box<dyn Fn(T) -> bool>,
18-
) -> Self {
19-
Self {
20-
neighbours,
21-
cost,
22-
is_end,
23-
}
13+
pub fn new(neighbours: Box<dyn Fn(T) -> Vec<T>>, cost: Box<dyn Fn(T, T) -> usize>) -> Self {
14+
Self { neighbours, cost }
2415
}
2516

26-
pub fn cost(&self, starts: Vec<T>) -> Option<usize>
17+
pub fn cost(&self, starts: Vec<T>, is_end: &dyn Fn(T) -> bool) -> Option<usize>
2718
where
2819
T: Hash + Eq + PartialEq + Ord + Copy + Debug,
2920
{
@@ -36,7 +27,7 @@ impl<T> Dijkstra<T> {
3627
}
3728

3829
while let Some(State { cost, node }) = heap.pop() {
39-
if (self.is_end)(node) {
30+
if is_end(node) {
4031
return Some(cost);
4132
}
4233

@@ -56,7 +47,7 @@ impl<T> Dijkstra<T> {
5647

5748
/// It returns every possible visited node
5849
/// Even if there is a many possible ways to reach end
59-
pub fn all_paths(&self, starts: Vec<T>) -> Vec<VecDeque<T>>
50+
pub fn all_paths(&self, starts: Vec<T>, is_end: &dyn Fn(T) -> bool) -> Vec<VecDeque<T>>
6051
where
6152
T: Hash + Eq + PartialEq + Ord + Debug + Copy,
6253
{
@@ -74,7 +65,7 @@ impl<T> Dijkstra<T> {
7465
let mut end_nodes: Vec<T> = Vec::new();
7566

7667
while let Some(State { cost, node }) = heap.pop() {
77-
if (self.is_end)(node) {
68+
if is_end(node) {
7869
lowest = Some(cost);
7970
end_nodes.push(node);
8071

@@ -171,10 +162,10 @@ mod test {
171162
_ => unreachable!("Invalid node"),
172163
}),
173164
Box::new(|_: char, _: char| 1),
174-
Box::new(|node: char| node == '<'),
175165
);
166+
let is_end = |node: char| node == '<';
176167

177-
let paths = dijkstra.all_paths(vec!['A']);
168+
let paths = dijkstra.all_paths(vec!['A'], &is_end);
178169

179170
assert_eq!(paths.len(), 2);
180171
assert!(paths.contains(&VecDeque::from(vec!['A', '^', 'v', '<'])));

0 commit comments

Comments
 (0)