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
396fn 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