Skip to content

Commit 45b27f0

Browse files
committed
Add run-of-the-mill Dijkstra
1 parent 451c961 commit 45b27f0

1 file changed

Lines changed: 99 additions & 3 deletions

File tree

day20/src/day20.rs

Lines changed: 99 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,97 @@
1-
use std::{env, fs, process};
1+
use std::{cmp::Ordering, collections::{BinaryHeap, HashSet}, env, fs, ops::Index, process};
2+
3+
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
4+
struct Vec2<T> {
5+
x: T,
6+
y: T,
7+
}
8+
9+
impl<T> Vec2<T> {
10+
fn new(x: T, y: T) -> Self {
11+
Self { x, y }
12+
}
13+
}
14+
15+
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
16+
struct Racetrack {
17+
rows: Vec<Vec<char>>,
18+
}
19+
20+
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
21+
struct Node {
22+
pos: Vec2<i32>,
23+
picos: i32,
24+
}
25+
26+
impl Ord for Node {
27+
fn cmp(&self, other: &Self) -> Ordering {
28+
self.picos.cmp(&other.picos)
29+
}
30+
}
31+
32+
impl PartialOrd for Node {
33+
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
34+
Some(self.cmp(other))
35+
}
36+
}
37+
38+
impl Racetrack {
39+
fn height(&self) -> i32 {
40+
self.rows.len() as i32
41+
}
42+
43+
fn width(&self) -> i32 {
44+
self.rows[0].len() as i32
45+
}
46+
47+
fn in_bounds(&self, pos: Vec2<i32>) -> bool {
48+
pos.x >= 0 && pos.x < self.width() && pos.y >= 0 && pos.y < self.height()
49+
}
50+
51+
fn locate(&self, c: char) -> Option<Vec2<i32>> {
52+
self.rows.iter()
53+
.enumerate()
54+
.find_map(|(y, row)| row.iter().enumerate().find(|(_, &cell)| cell == c).map(|(x, _)| Vec2::new(x as i32, y as i32)))
55+
}
56+
57+
fn shortest_path(&self, start: Vec2<i32>, end: Vec2<i32>) -> Option<i32> {
58+
// Your run-of-the-mill Dijkstra implementation
59+
60+
let mut queue = BinaryHeap::new();
61+
let mut visited = HashSet::new();
62+
63+
queue.push(Node { pos: start, picos: 0 });
64+
visited.insert(start);
65+
66+
while let Some(node) = queue.pop() {
67+
if node.pos == end {
68+
return Some(node.picos);
69+
}
70+
71+
for dy in -1..=1 {
72+
for dx in -1..=1 {
73+
if (dx != 0) ^ (dy != 0) {
74+
let neigh = Vec2::new(node.pos.x + dx, node.pos.y + dy);
75+
if !visited.contains(&neigh) && self.in_bounds(neigh) && self[neigh] != '#' {
76+
visited.insert(neigh);
77+
queue.push(Node { pos: neigh, picos: node.picos + 1 });
78+
}
79+
}
80+
}
81+
}
82+
}
83+
84+
None
85+
}
86+
}
87+
88+
impl Index<Vec2<i32>> for Racetrack {
89+
type Output = char;
90+
91+
fn index(&self, index: Vec2<i32>) -> &char {
92+
&self.rows[index.y as usize][index.x as usize]
93+
}
94+
}
295

396
fn main() {
497
let args: Vec<_> = env::args().collect();
@@ -8,7 +101,10 @@ fn main() {
8101
}
9102

10103
let raw = fs::read_to_string(&args[1]).unwrap();
11-
let matrix: Vec<_> = raw.trim().split("\n").collect();
104+
let track = Racetrack { rows: raw.trim().split("\n").map(|row| row.chars().collect()).collect() };
105+
106+
let start = track.locate('S').unwrap();
107+
let end = track.locate('E').unwrap();
12108

13-
println!("{matrix:?}");
109+
println!("Shortest: {}", track.shortest_path(start, end).unwrap());
14110
}

0 commit comments

Comments
 (0)