Skip to content

Commit 2275dce

Browse files
committed
[2021] Redo day 15 with Dijkstra's
i do rember being sick when writing the old version, so maybe that explains it
1 parent fdfd526 commit 2275dce

File tree

1 file changed

+69
-26
lines changed

1 file changed

+69
-26
lines changed

aoc_2021/src/day_15.rs

Lines changed: 69 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,89 @@
1+
use std::collections::BinaryHeap;
2+
3+
use hashbrown::HashMap;
4+
use nd_vec::{vector, Vector};
5+
16
use aoc_lib::{direction::Direction, matrix::Matrix};
27
use common::{solution, Answer};
3-
use hashbrown::HashMap;
4-
use nd_vec::vector;
58

69
solution!("Chiton", 15);
710

11+
type Point = Vector<usize, 2>;
12+
813
fn part_a(input: &str) -> Answer {
914
let matrix = Matrix::new_chars(input, |chr| chr.to_digit(10).unwrap() as u8);
15+
solve(matrix.size, |pos| matrix.get(pos).copied()).into()
16+
}
17+
18+
fn part_b(input: &str) -> Answer {
19+
let matrix = Matrix::new_chars(input, |chr| chr.to_digit(10).unwrap() as u8);
20+
solve(matrix.size * 5, |pos| {
21+
let (cx, cy) = (pos.x() / matrix.size.x(), pos.y() / matrix.size.y());
22+
if cx > 4 || cy > 4 {
23+
return None;
24+
};
25+
26+
let pos = vector!(pos.x() % matrix.size.x(), pos.y() % matrix.size.y());
27+
matrix
28+
.get(pos)
29+
.map(|x| (x + cx as u8 + cy as u8 - 1) % 9 + 1)
30+
})
31+
.into()
32+
}
1033

11-
let mut out = usize::MAX;
12-
let mut visited = HashMap::new();
13-
let mut queue = Vec::new();
14-
queue.push((vector!(0, 0), 0));
34+
fn solve(size: Point, get: impl Fn(Point) -> Option<u8>) -> u32 {
35+
let mut seen = HashMap::new();
36+
let mut queue = BinaryHeap::new();
1537

16-
while let Some((pos, cost)) = queue.pop() {
17-
if pos == matrix.size - vector!(1, 1) {
18-
out = out.min(cost);
19-
continue;
38+
seen.insert(vector!(0, 0), 0);
39+
queue.push(QueueItem {
40+
pos: vector!(0, 0),
41+
distance: 0,
42+
});
43+
44+
while let Some(item) = queue.pop() {
45+
if item.pos == size - vector!(1, 1) {
46+
return item.distance;
2047
}
2148

22-
visited.insert(pos, cost);
2349
for dir in Direction::ALL {
24-
if let Some((next, new_cost)) = dir
25-
.try_advance(pos)
26-
.and_then(|x| Some((x, cost + *matrix.get(x)? as usize)))
27-
{
28-
if let Some(prev) = visited.get(&next) {
29-
if *prev <= new_cost {
30-
continue;
31-
}
32-
}
33-
34-
queue.push((next, new_cost));
50+
let Some((pos, cost)) = dir.try_advance(item.pos).and_then(|x| Some((x, get(x)?)))
51+
else {
52+
continue;
53+
};
54+
55+
let dist = seen.entry(pos).or_insert(u32::MAX);
56+
let next_dist = item.distance + cost as u32;
57+
58+
if next_dist < *dist {
59+
*dist = next_dist;
60+
queue.push(QueueItem {
61+
pos,
62+
distance: next_dist,
63+
});
3564
}
3665
}
3766
}
3867

39-
out.into()
68+
unreachable!()
69+
}
70+
71+
#[derive(PartialEq, Eq)]
72+
struct QueueItem {
73+
pos: Point,
74+
distance: u32,
4075
}
4176

42-
fn part_b(_input: &str) -> Answer {
43-
Answer::Unimplemented
77+
impl Ord for QueueItem {
78+
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
79+
other.distance.cmp(&self.distance)
80+
}
81+
}
82+
83+
impl PartialOrd for QueueItem {
84+
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
85+
Some(self.cmp(other))
86+
}
4487
}
4588

4689
#[cfg(test)]
@@ -67,6 +110,6 @@ mod test {
67110

68111
#[test]
69112
fn part_b() {
70-
assert_eq!(super::part_b(CASE), ().into());
113+
assert_eq!(super::part_b(CASE), 315.into());
71114
}
72115
}

0 commit comments

Comments
 (0)