Skip to content

Commit 2539c2c

Browse files
committed
fix: fix dijkstra all paths function and solve 16/2024
1 parent 94286d9 commit 2539c2c

File tree

4 files changed

+167
-73
lines changed

4 files changed

+167
-73
lines changed

readme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
| [Day 13: Claw Contraption](src/solutions/year2024/day13.rs) | ⭐⭐ | 0.241 | 0.331 |
2727
| [Day 14: Restroom Redoubt](src/solutions/year2024/day14.rs) | ⭐⭐ | 0.172 | 102.252 |
2828
| [Day 15: Warehouse Woes](src/solutions/year2024/day15.rs) | ⭐⭐ | 7.226 | 9.084 |
29-
| [Day 16: Reindeer Maze](src/solutions/year2024/day16.rs) | | 6.478 | - |
29+
| [Day 16: Reindeer Maze](src/solutions/year2024/day16.rs) | | 6.478 | 22716.831 |
3030
| [Day 17: Chronospatial Computer](src/solutions/year2024/day17.rs) | - | - | - |
3131
| [Day 18: RAM Run](src/solutions/year2024/day18.rs) | ⭐⭐ | 2.487 | 204.885 |
3232
| [Day 19: Linen Layout](src/solutions/year2024/day19.rs) | ⭐⭐ | 2.923 | 22.751 |

src/solutions/year2024/day16.rs

Lines changed: 7 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@ 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;
65
use crate::utils::vector::Vector;
76
use itertools::Itertools;
8-
use std::collections::{HashSet, VecDeque};
97

108
pub struct Day16;
119

@@ -32,16 +30,6 @@ impl Solution for Day16 {
3230
})
3331
.collect_vec();
3432

35-
// let mut grid = grid.clone();
36-
// grid.modify(vector.position(), 'S');
37-
// for re in &result {
38-
// grid.modify(re.position(), 'O')
39-
// }
40-
//
41-
// println!("{} - {}", vector, result.len());
42-
// println!("{}", grid);
43-
//
44-
4533
result
4634
};
4735

@@ -96,41 +84,14 @@ impl Solution for Day16 {
9684
let is_end = |vector: Vector| vector.position() == end;
9785
let dijkstra: Dijkstra<Vector> = Dijkstra::new(&adjacency, &cost, &is_end);
9886

99-
let paths = dijkstra.all_path(vec![start]);
100-
101-
let mut queue: VecDeque<Point> = VecDeque::from([end]);
102-
let mut path: HashSet<Point> = HashSet::from([end]);
103-
104-
while let Some(current) = queue.pop_back() {
105-
let before_ends = paths
106-
.iter()
107-
.filter_map(|(to, from)| {
108-
if to.position() == current {
109-
if let Some(from) = from {
110-
if !path.contains(&from.position()) {
111-
return Some(from.position());
112-
}
113-
}
114-
}
115-
116-
None
117-
})
118-
.collect_vec();
119-
120-
path.extend(before_ends.clone());
121-
queue.extend(before_ends);
122-
}
123-
124-
// let mut grid = grid.clone();
125-
// for re in &path {
126-
// grid.modify(*re, 'O')
127-
// }
128-
129-
// println!("{}", grid);
130-
//
131-
// println!("{:?}", path.len());
87+
let paths = dijkstra.all_paths(vec![start]);
13288

133-
path.len().to_string()
89+
paths
90+
.iter()
91+
.flat_map(|path| path.iter().map(|p| p.position()))
92+
.unique()
93+
.count()
94+
.to_string()
13495
}
13596
}
13697

@@ -161,7 +122,6 @@ mod tests {
161122
}
162123

163124
#[test]
164-
#[ignore]
165125
fn part_two_example_1() {
166126
assert_eq!("45", Day16.part_two(FIRST_EXAMPLE));
167127
}
@@ -190,7 +150,6 @@ mod tests {
190150
}
191151

192152
#[test]
193-
#[ignore]
194153
fn part_two_example_2() {
195154
assert_eq!("64", Day16.part_two(SECOND_EXAMPLE));
196155
}

src/solutions/year2024/day21.rs

Lines changed: 53 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,22 @@ const NUM_PAD: &str = r#"789
1818
const NUM_PAD_ELEMENTS: [u8; 11] = [
1919
b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'A',
2020
];
21-
const ARROW_PAD: &str = r#".^A
21+
const KEY_PAD: &str = r#".^A
2222
<v>"#;
23-
const ARROW_PAD_ELEMENTS: [u8; 5] = [b'^', b'v', b'<', b'>', b'A'];
23+
const KEY_PAD_ELEMENTS: [u8; 5] = [b'^', b'v', b'<', b'>', b'A'];
2424

2525
pub struct Day21;
2626

2727
impl Solution for Day21 {
2828
fn part_one(&self, input: &str) -> String {
29-
let pads = vec![Pad::numeric(), Pad::arrow(), Pad::arrow()];
29+
let pads = vec![Pad::numeric(), Pad::key(), Pad::key()];
3030

3131
input
3232
.lines()
3333
.map(|line| {
3434
let path_len = self.path_len(line, &pads);
3535
let num: usize = line.trim_end_matches('A').parse().unwrap();
3636

37-
// println!("{} * {}", path_len, num);
3837
num * path_len
3938
})
4039
.sum::<usize>()
@@ -60,14 +59,12 @@ impl Day21 {
6059

6160
current.chars().count()
6261
}
62+
6363
fn path_for_str(&self, code: &str, pad: &Pad) -> Vec<Key> {
6464
let code = "A".to_owned() + code;
65-
let a_position = pad.position(b'A').unwrap();
6665

6766
let neighbours = |p: Point| pad.adjacent(&p);
68-
let distance = |p1: Point, p2: Point| {
69-
p1.manhattan_distance(&p2) as usize + p2.manhattan_distance(&a_position) as usize
70-
};
67+
let distance = |_, _| 1;
7168

7269
let a_star = AStarBuilder::init(&neighbours, &distance).build();
7370

@@ -133,8 +130,8 @@ impl Pad {
133130
}
134131
}
135132

136-
fn arrow() -> Self {
137-
let positions = Self::build_positions(ARROW_PAD, &ARROW_PAD_ELEMENTS);
133+
fn key() -> Self {
134+
let positions = Self::build_positions(KEY_PAD, &KEY_PAD_ELEMENTS);
138135
let adjacent = Self::build_adjacent(&positions);
139136

140137
Self {
@@ -182,9 +179,10 @@ impl Pad {
182179

183180
#[cfg(test)]
184181
mod tests {
185-
use crate::solutions::year2024::day21::Key::Activate;
182+
use crate::solutions::year2024::day21::Key::{Activate, Dir};
186183
use crate::solutions::year2024::day21::{Day21, Pad};
187184
use crate::solutions::Solution;
185+
use crate::utils::direction::Direction::{East, North, South, West};
188186

189187
const EXAMPLE: &str = r#"029A
190188
980A
@@ -201,20 +199,61 @@ mod tests {
201199
#[test]
202200
#[ignore]
203201
fn path_len() {
204-
let pads = vec![Pad::numeric(), Pad::arrow(), Pad::arrow()];
202+
let pads = vec![Pad::numeric(), Pad::key(), Pad::key()];
205203

206204
assert_eq!(68, Day21.path_len("029A", &pads));
207205
assert_eq!(60, Day21.path_len("980A", &pads));
208206
assert_eq!(68, Day21.path_len("179A", &pads));
209207
assert_eq!(64, Day21.path_len("456A", &pads));
210208
assert_eq!(64, Day21.path_len("379A", &pads));
209+
assert_eq!(78, Day21.path_len("739A", &pads));
211210
}
212211

213212
#[test]
214213
fn path_for_str() {
214+
let numeric = &Pad::numeric();
215+
let key = &Pad::key();
216+
217+
assert_eq!(Day21.path_for_str("AA", numeric), vec![Activate, Activate]);
218+
assert_eq!(
219+
Day21.path_for_str("A1", numeric),
220+
vec![Activate, Dir(North), Dir(West), Dir(West), Activate]
221+
);
222+
assert_eq!(
223+
Day21.path_for_str("A4", numeric),
224+
vec![
225+
Activate,
226+
Dir(North),
227+
Dir(North),
228+
Dir(West),
229+
Dir(West),
230+
Activate
231+
]
232+
);
233+
assert_eq!(
234+
Day21.path_for_str("A7", numeric),
235+
vec![
236+
Activate,
237+
Dir(North),
238+
Dir(North),
239+
Dir(North),
240+
Dir(West),
241+
Dir(West),
242+
Activate
243+
]
244+
);
215245
assert_eq!(
216-
Day21.path_for_str("AA", &Pad::numeric()),
217-
vec![Activate, Activate]
246+
Day21.path_for_str("<A", key),
247+
vec![
248+
Dir(South),
249+
Dir(West),
250+
Dir(West),
251+
Activate,
252+
Dir(East),
253+
Dir(East),
254+
Dir(North),
255+
Activate
256+
]
218257
);
219258
}
220259
}

src/utils/graphs/dijkstra.rs

Lines changed: 106 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::utils::graphs::state_utils::State;
2-
use std::collections::{BinaryHeap, HashMap};
2+
use std::cmp::Ordering;
3+
use std::collections::{BinaryHeap, HashMap, VecDeque};
34
use std::fmt::Debug;
45
use std::hash::Hash;
56

@@ -56,25 +57,27 @@ impl<'a, T> Dijkstra<'a, T> {
5657
/// It returns every possible visited node
5758
/// Even if there is a many possible ways to reach end
5859
/// FIXME: is not working in valid way
59-
pub fn all_path(&self, starts: Vec<T>) -> HashMap<T, Option<T>>
60+
pub fn all_paths(&self, starts: Vec<T>) -> Vec<VecDeque<T>>
6061
where
6162
T: Hash + Eq + PartialEq + Ord + Debug + Copy,
6263
{
6364
let mut current_costs: HashMap<T, usize> = HashMap::new();
6465
let mut heap = BinaryHeap::new();
65-
let mut come_from = HashMap::new();
66+
let mut come_from: HashMap<T, Vec<T>> = HashMap::new();
6667

67-
for start in starts {
68+
for start in starts.clone() {
6869
current_costs.insert(start, 0);
6970
heap.push(State::new(start, 0));
70-
come_from.insert(start, None);
71+
come_from.insert(start, Vec::new());
7172
}
7273

7374
let mut lowest: Option<usize> = None;
75+
let mut end_nodes: Vec<T> = Vec::new();
7476

7577
while let Some(State { cost, node }) = heap.pop() {
7678
if (self.is_end)(node) {
7779
lowest = Some(cost);
80+
end_nodes.push(node);
7881

7982
continue;
8083
}
@@ -87,14 +90,107 @@ impl<'a, T> Dijkstra<'a, T> {
8790
let neighbour_cost = cost + (self.cost)(node, neighbour);
8891
let current_neighbour_cost = current_costs.get(&neighbour).unwrap_or(&usize::MAX);
8992

90-
if neighbour_cost < *current_neighbour_cost {
91-
*current_costs.entry(neighbour).or_insert(usize::MAX) = neighbour_cost;
92-
come_from.insert(neighbour, Some(node));
93-
heap.push(State::new(neighbour, neighbour_cost));
93+
match neighbour_cost.cmp(current_neighbour_cost) {
94+
Ordering::Less => {
95+
*current_costs.entry(neighbour).or_insert(usize::MAX) = neighbour_cost;
96+
come_from.entry(neighbour).or_default().push(node);
97+
heap.push(State::new(neighbour, neighbour_cost));
98+
}
99+
Ordering::Equal => {
100+
come_from.entry(neighbour).or_default().push(node);
101+
}
102+
_ => {}
103+
}
104+
}
105+
}
106+
107+
self.build_paths(&come_from, starts, end_nodes)
108+
}
109+
110+
fn build_paths(
111+
&self,
112+
come_from: &HashMap<T, Vec<T>>,
113+
start_nodes: Vec<T>,
114+
end_nodes: Vec<T>,
115+
) -> Vec<VecDeque<T>>
116+
where
117+
T: Hash + Eq + PartialEq + Ord + Debug + Copy,
118+
{
119+
let mut paths: Vec<VecDeque<T>> = Vec::new();
120+
121+
for start in start_nodes {
122+
for end in &end_nodes {
123+
Self::visit(
124+
start,
125+
*end,
126+
Vec::new(),
127+
VecDeque::new(),
128+
&mut paths,
129+
come_from,
130+
);
131+
}
132+
}
133+
134+
paths
135+
}
136+
137+
fn visit(
138+
from: T,
139+
end: T,
140+
mut visited: Vec<T>,
141+
mut path: VecDeque<T>,
142+
paths: &mut Vec<VecDeque<T>>,
143+
come_from: &HashMap<T, Vec<T>>,
144+
) where
145+
T: Hash + Eq + PartialEq + Ord + Debug + Copy,
146+
{
147+
{
148+
visited.push(from);
149+
path.push_back(from);
150+
151+
if from == end {
152+
paths.push(path.clone());
153+
154+
return;
155+
}
156+
157+
for p in come_from
158+
.iter()
159+
.filter(|(_, froms)| froms.contains(&from))
160+
.map(|(to, _)| to)
161+
{
162+
if !visited.contains(p) {
163+
Self::visit(*p, end, visited.clone(), path.clone(), paths, come_from);
94164
}
95165
}
96166
}
167+
}
168+
}
97169

98-
come_from
170+
#[cfg(test)]
171+
mod test {
172+
use crate::utils::graphs::dijkstra::Dijkstra;
173+
use std::collections::VecDeque;
174+
175+
#[test]
176+
fn all_paths() {
177+
let dijkstra = Dijkstra::new(
178+
&|node: char| match node {
179+
'A' => vec!['^', '>'],
180+
'^' => vec!['A', 'v'],
181+
'>' => vec!['A', 'v'],
182+
'v' => vec!['^', '>', '<'],
183+
'<' => vec!['v'],
184+
_ => unreachable!("Invalid node"),
185+
},
186+
&|_: char, _: char| 1,
187+
&|node: char| node == '<',
188+
);
189+
190+
let paths = dijkstra.all_paths(vec!['A']);
191+
192+
assert_eq!(paths.len(), 2);
193+
assert!(paths.contains(&VecDeque::from(vec!['A', '^', 'v', '<'])));
194+
assert!(paths.contains(&VecDeque::from(vec!['A', '>', 'v', '<'])));
99195
}
100196
}

0 commit comments

Comments
 (0)