Skip to content

Commit c217286

Browse files
committed
refactor(16/2024): remove code duplications
1 parent 8e0d3bb commit c217286

File tree

3 files changed

+87
-92
lines changed

3 files changed

+87
-92
lines changed

src/solutions/year2023/day17.rs

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,26 +10,30 @@ pub struct Day17;
1010
impl Solution for Day17 {
1111
fn part_one(&self, input: &str) -> String {
1212
let grid: Grid<u8> = Self::parse(input);
13+
let grid_clone = grid.clone();
14+
let grid_clone_2 = grid.clone();
1315

14-
let adjacency = |node: Node| -> Vec<Node> {
16+
let adjacency = move |node: Node| -> Vec<Node> {
1517
let vec: Vec<Node> = if node.forward_count < 3 {
1618
vec![node.left(), node.right(), node.forward()]
1719
} else {
1820
vec![node.left(), node.right()]
1921
};
2022

21-
Self::filter_out_outside_grid(vec, &grid)
23+
Self::filter_out_outside_grid(vec, &grid_clone)
2224
};
2325

24-
let is_end = |node: Node| -> bool { Self::is_end_node(node, &grid) };
26+
let is_end = move |node: Node| -> bool { Self::is_end_node(node, &grid_clone_2) };
2527

26-
Self::solve(&grid, &adjacency, &is_end)
28+
Self::solve(&grid, Box::new(adjacency), Box::new(is_end))
2729
}
2830

2931
fn part_two(&self, input: &str) -> String {
3032
let grid: Grid<u8> = Self::parse(input);
33+
let grid_clone = grid.clone();
34+
let grid_clone_2 = grid.clone();
3135

32-
let adjacency = |node: Node| -> Vec<Node> {
36+
let adjacency = move |node: Node| -> Vec<Node> {
3337
let vec: Vec<Node> = if node.forward_count < 4 {
3438
vec![node.forward()]
3539
} else if node.forward_count >= 4 && node.forward_count < 10 {
@@ -38,13 +42,14 @@ impl Solution for Day17 {
3842
vec![node.left(), node.right()]
3943
};
4044

41-
Self::filter_out_outside_grid(vec, &grid)
45+
Self::filter_out_outside_grid(vec, &grid_clone)
4246
};
4347

44-
let is_end =
45-
|node: Node| -> bool { node.forward_count >= 4 && Self::is_end_node(node, &grid) };
48+
let is_end = move |node: Node| -> bool {
49+
node.forward_count >= 4 && Self::is_end_node(node, &grid_clone_2)
50+
};
4651

47-
Self::solve(&grid, &adjacency, &is_end)
52+
Self::solve(&grid, Box::new(adjacency), Box::new(is_end))
4853
}
4954
}
5055

@@ -55,12 +60,15 @@ impl Day17 {
5560

5661
fn solve(
5762
grid: &Grid<u8>,
58-
adjacency: &dyn Fn(Node) -> Vec<Node>,
59-
is_end: &dyn Fn(Node) -> bool,
63+
adjacency: Box<dyn Fn(Node) -> Vec<Node>>,
64+
is_end: Box<dyn Fn(Node) -> bool>,
6065
) -> String {
6166
let start_point = grid.surface().top_left_corner();
62-
let cost = |_, next: Node| *grid.get_for_point(&next.vector.position()).unwrap() as usize;
63-
let dijkstra: Dijkstra<Node> = Dijkstra::new(adjacency, &cost, is_end);
67+
let grid_clone = grid.clone();
68+
let cost = move |_, next: Node| {
69+
*grid_clone.get_for_point(&next.vector.position()).unwrap() as usize
70+
};
71+
let dijkstra: Dijkstra<Node> = Dijkstra::new(adjacency, Box::new(cost), Box::new(is_end));
6472

6573
let starts = vec![
6674
Node::new(start_point, Direction::East),

src/solutions/year2024/day16.rs

Lines changed: 48 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -2,96 +2,84 @@ use crate::solutions::Solution;
22
use crate::utils::direction::Direction::East;
33
use crate::utils::graphs::dijkstra::Dijkstra;
44
use crate::utils::grid::Grid;
5+
use crate::utils::point::Point;
56
use crate::utils::vector::Vector;
67
use itertools::Itertools;
78

89
pub struct Day16;
910

1011
impl Solution for Day16 {
1112
fn part_one(&self, input: &str) -> String {
12-
let grid: Grid<char> = Grid::from(input);
13-
let start = grid.get_first_position(&'S').unwrap();
14-
let start = Vector::new(start, East);
15-
let end = grid.get_first_position(&'E').unwrap();
16-
17-
let adjacency = |vector: Vector| {
18-
let vectors = vec![
19-
vector.forward(),
20-
vector.rotate_cw().forward(),
21-
vector.rotate_ccw().forward(),
22-
];
23-
24-
let result = vectors
25-
.into_iter()
26-
.filter(|vec| {
27-
let element = grid.get_for_point(&vec.position());
28-
29-
element == Some(&'.') || element == Some(&'E')
30-
})
31-
.collect_vec();
32-
33-
result
34-
};
35-
36-
let cost = |current: Vector, next: Vector| {
37-
if current.forward() == next {
38-
return 1;
39-
}
40-
41-
1001
42-
};
43-
44-
let is_end = |vector: Vector| vector.position() == end;
45-
46-
let dijkstra: Dijkstra<Vector> = Dijkstra::new(&adjacency, &cost, &is_end);
13+
let (grid, start, end) = Self::setup_grid(input);
14+
let dijkstra = Self::create_dijkstra(grid, end);
4715

4816
dijkstra.cost(vec![start]).unwrap().to_string()
4917
}
5018

5119
fn part_two(&self, input: &str) -> String {
20+
let (grid, start, end) = Self::setup_grid(input);
21+
let dijkstra = Self::create_dijkstra(grid, end);
22+
23+
dijkstra
24+
.all_paths(vec![start])
25+
.iter()
26+
.flat_map(|path| path.iter().map(|p| p.position()))
27+
.unique()
28+
.count()
29+
.to_string()
30+
}
31+
}
32+
33+
impl Day16 {
34+
fn setup_grid(input: &str) -> (Grid<char>, Vector, Point) {
5235
let grid: Grid<char> = Grid::from(input);
5336
let start = grid.get_first_position(&'S').unwrap();
5437
let start = Vector::new(start, East);
5538
let end = grid.get_first_position(&'E').unwrap();
5639

57-
let adjacency = |vector: Vector| {
40+
(grid, start, end)
41+
}
42+
43+
fn create_dijkstra(grid: Grid<char>, end: Point) -> Dijkstra<Vector> {
44+
let adjacency = Self::adjacency_closure(grid);
45+
let cost = Self::cost_closure();
46+
let is_end = Self::is_end_closure(end);
47+
48+
Dijkstra::new(adjacency, cost, is_end)
49+
}
50+
51+
fn adjacency_closure(grid: Grid<char>) -> Box<dyn Fn(Vector) -> Vec<Vector>> {
52+
Box::new(move |vector: Vector| {
5853
let vectors = vec![
5954
vector.forward(),
6055
vector.rotate_cw().forward(),
6156
vector.rotate_ccw().forward(),
6257
];
6358

64-
let result = vectors
59+
vectors
6560
.into_iter()
6661
.filter(|vec| {
6762
let element = grid.get_for_point(&vec.position());
68-
6963
element == Some(&'.') || element == Some(&'E')
7064
})
71-
.collect_vec();
72-
73-
result
74-
};
75-
76-
let cost = |current: Vector, next: Vector| {
77-
if current.forward() == next {
78-
return 1;
79-
}
80-
81-
1001
82-
};
83-
84-
let is_end = |vector: Vector| vector.position() == end;
85-
let dijkstra: Dijkstra<Vector> = Dijkstra::new(&adjacency, &cost, &is_end);
65+
.collect_vec()
66+
})
67+
}
8668

87-
let paths = dijkstra.all_paths(vec![start]);
69+
fn cost_closure() -> Box<dyn Fn(Vector, Vector) -> usize> {
70+
Box::new(
71+
move |current: Vector, next: Vector| {
72+
if current.forward() == next {
73+
1
74+
} else {
75+
1001
76+
}
77+
},
78+
)
79+
}
8880

89-
paths
90-
.iter()
91-
.flat_map(|path| path.iter().map(|p| p.position()))
92-
.unique()
93-
.count()
94-
.to_string()
81+
fn is_end_closure(end: Point) -> Box<dyn Fn(Vector) -> bool> {
82+
Box::new(move |vector: Vector| vector.position() == end)
9583
}
9684
}
9785

src/utils/graphs/dijkstra.rs

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@ use std::collections::{BinaryHeap, HashMap, VecDeque};
44
use std::fmt::Debug;
55
use std::hash::Hash;
66

7-
pub struct Dijkstra<'a, T> {
8-
neighbours: &'a dyn Fn(T) -> Vec<T>,
9-
cost: &'a dyn Fn(T, T) -> usize,
10-
is_end: &'a dyn Fn(T) -> bool,
7+
pub struct Dijkstra<T> {
8+
neighbours: Box<dyn Fn(T) -> Vec<T>>,
9+
cost: Box<dyn Fn(T, T) -> usize>,
10+
is_end: Box<dyn Fn(T) -> bool>,
1111
}
1212

13-
impl<'a, T> Dijkstra<'a, T> {
13+
impl<T> Dijkstra<T> {
1414
pub fn new(
15-
neighbours: &'a dyn Fn(T) -> Vec<T>,
16-
cost: &'a dyn Fn(T, T) -> usize,
17-
is_end: &'a dyn Fn(T) -> bool,
15+
neighbours: Box<dyn Fn(T) -> Vec<T>>,
16+
cost: Box<dyn Fn(T, T) -> usize>,
17+
is_end: Box<dyn Fn(T) -> bool>,
1818
) -> Self {
1919
Self {
2020
neighbours,
@@ -56,7 +56,6 @@ impl<'a, T> Dijkstra<'a, T> {
5656

5757
/// It returns every possible visited node
5858
/// Even if there is a many possible ways to reach end
59-
/// FIXME: is not working in valid way
6059
pub fn all_paths(&self, starts: Vec<T>) -> Vec<VecDeque<T>>
6160
where
6261
T: Hash + Eq + PartialEq + Ord + Debug + Copy,
@@ -135,29 +134,29 @@ impl<'a, T> Dijkstra<'a, T> {
135134
}
136135

137136
fn visit(
138-
from: T,
139137
end: T,
138+
current: T,
140139
visited: &mut Vec<T>,
141140
path: &mut VecDeque<T>,
142141
paths: &mut Vec<VecDeque<T>>,
143142
come_from: &HashMap<T, Vec<T>>,
144143
) where
145144
T: Hash + Eq + PartialEq + Ord + Debug + Copy,
146145
{
147-
visited.push(end);
148-
path.push_front(end);
146+
visited.push(current);
147+
path.push_front(current);
149148

150-
if from == end {
149+
if end == current {
151150
paths.push(path.clone());
152151
path.pop_front();
153152
visited.pop();
154153

155154
return;
156155
}
157156

158-
for p in come_from.get(&end).unwrap_or(&Vec::new()) {
157+
for p in come_from.get(&current).unwrap_or(&Vec::new()) {
159158
if !visited.contains(p) {
160-
Self::visit(from, *p, visited, path, paths, come_from);
159+
Self::visit(end, *p, visited, path, paths, come_from);
161160
}
162161
}
163162

@@ -174,16 +173,16 @@ mod test {
174173
#[test]
175174
fn all_paths() {
176175
let dijkstra = Dijkstra::new(
177-
&|node: char| match node {
176+
Box::new(|node: char| match node {
178177
'A' => vec!['^', '>'],
179178
'^' => vec!['A', 'v'],
180179
'>' => vec!['A', 'v'],
181180
'v' => vec!['^', '>', '<'],
182181
'<' => vec!['v'],
183182
_ => unreachable!("Invalid node"),
184-
},
185-
&|_: char, _: char| 1,
186-
&|node: char| node == '<',
183+
}),
184+
Box::new(|_: char, _: char| 1),
185+
Box::new(|node: char| node == '<'),
187186
);
188187

189188
let paths = dijkstra.all_paths(vec!['A']);

0 commit comments

Comments
 (0)