@@ -4,27 +4,64 @@ use std::{
44 rc:: { Rc , Weak } ,
55} ;
66
7+ #[ allow( dead_code) ]
78#[ derive( PartialEq ) ]
89pub enum MazeMoveDir {
910 Forward ,
1011 Backward ,
1112}
1213
13- pub trait Maze < const DIMS : usize > {
14- fn can_move (
15- & self ,
16- point : & [ usize ; DIMS ] ,
17- dimension : usize ,
18- direction : MazeMoveDir ,
19- ) -> Option < bool > ;
20- }
21-
22- struct WalkMaze < const DIMS : usize > {
14+ pub struct Maze < const DIMS : usize > {
2315 walks : std:: collections:: HashSet < ( [ usize ; DIMS ] , [ usize ; DIMS ] ) > ,
2416 lengths : [ usize ; DIMS ] ,
2517}
2618
27- impl < const DIMS : usize > WalkMaze < DIMS > {
19+ #[ allow( dead_code) ]
20+ impl < const DIMS : usize > Maze < DIMS > {
21+ // Generate a maze with the provided number of side lengths.
22+ pub fn new ( lengths : & [ usize ; DIMS ] , rng : & mut impl rand:: Rng ) -> Maze < DIMS > {
23+ let mut maze = Maze :: < DIMS > {
24+ lengths : * lengths,
25+ walks : Default :: default ( ) ,
26+ } ;
27+
28+ let cell_count = lengths. iter ( ) . product ( ) ;
29+
30+ // Indexed by dimension sums (higher is higher power).
31+ let mut cells = HashMap :: < [ usize ; DIMS ] , MazeGenCellRef > :: with_capacity ( cell_count) ;
32+ for index in 0 ..cell_count {
33+ let pos = unwrap_index ( lengths, index) . unwrap ( ) ;
34+ cells. insert ( pos, MazeGenCell :: new ( index) ) ;
35+ }
36+
37+ let mut pending_edges = BinaryHeap :: with_capacity ( cell_count * DIMS ) ;
38+ for index in 0 ..cell_count {
39+ for dim in 0 ..DIMS {
40+ pending_edges. push ( ( rng. next_u32 ( ) , index, dim) )
41+ }
42+ }
43+
44+ while let Some ( ( _, target_index, dim) ) = pending_edges. pop ( ) {
45+ let a = unwrap_index ( lengths, target_index) . unwrap ( ) ;
46+ // Skip the ends of each dimension, as that's checking outside the bounds of the space.
47+ // In the future do this check on insertion into the heap.
48+ if a[ dim] == lengths[ dim] {
49+ continue ;
50+ }
51+ let mut b = a;
52+ b[ dim] += 1 ;
53+ if let Some ( cell_a) = cells. get ( & a) {
54+ if let Some ( cell_b) = cells. get ( & b) {
55+ if MazeGenCell :: try_merge ( cell_a, cell_b) {
56+ maze. walks . insert ( ( a, b) ) ;
57+ }
58+ }
59+ }
60+ }
61+
62+ maze
63+ }
64+
2865 fn check_pair ( & self , a : & [ usize ; DIMS ] , b : & [ usize ; DIMS ] ) -> Option < bool > {
2966 for index in 0 ..DIMS {
3067 let length = self . lengths [ index] ;
@@ -35,21 +72,16 @@ impl<const DIMS: usize> WalkMaze<DIMS> {
3572
3673 // Check for either direction because it's cheaper to check twice
3774 // than store an exponential memory problem.
38- return Some (
39- self . walks . contains ( & ( a. clone ( ) , b. clone ( ) ) )
40- || self . walks . contains ( & ( b. clone ( ) , a. clone ( ) ) ) ,
41- ) ;
75+ Some ( self . walks . contains ( & ( * a, * b) ) || self . walks . contains ( & ( * b, * a) ) )
4276 }
43- }
4477
45- impl < const DIMS : usize > Maze < DIMS > for WalkMaze < DIMS > {
46- fn can_move (
78+ pub fn can_move (
4779 & self ,
4880 point : & [ usize ; DIMS ] ,
4981 dimension : usize ,
5082 direction : MazeMoveDir ,
5183 ) -> Option < bool > {
52- let mut target_point = point. clone ( ) ;
84+ let mut target_point = * point;
5385 if let Some ( shift_axis) = target_point. get_mut ( dimension) {
5486 if let Some ( new_shifted) = match direction {
5587 MazeMoveDir :: Forward => shift_axis. checked_add ( 1 ) ,
@@ -59,7 +91,7 @@ impl<const DIMS: usize> Maze<DIMS> for WalkMaze<DIMS> {
5991 return self . check_pair ( point, & target_point) ;
6092 }
6193 }
62- return None ;
94+ None
6395 }
6496}
6597
@@ -115,51 +147,6 @@ fn unwrap_index<const DIMS: usize>(lengths: &[usize; DIMS], index: usize) -> Opt
115147 }
116148}
117149
118- // Generate a maze with the provided number of side lengths.
119- pub fn generate_maze < const DIMS : usize > (
120- lengths : & [ usize ; DIMS ] ,
121- rng : & mut impl rand:: Rng ,
122- ) -> impl Maze < DIMS > {
123- let mut maze = WalkMaze :: < DIMS > {
124- lengths : lengths. clone ( ) ,
125- walks : Default :: default ( ) ,
126- } ;
127-
128- let cell_count = lengths. iter ( ) . product ( ) ;
129-
130- // Indexed by dimension sums (higher is higher power).
131- let mut cells = HashMap :: < [ usize ; DIMS ] , MazeGenCellRef > :: with_capacity ( cell_count) ;
132- for index in 0 ..cell_count {
133- let pos = unwrap_index ( lengths, index) . unwrap ( ) ;
134- cells. insert ( pos, MazeGenCell :: new ( index) ) ;
135- }
136-
137- let mut pending_edges = BinaryHeap :: with_capacity ( cell_count * DIMS ) ;
138- for index in 0 ..cell_count {
139- for dim in 0 ..DIMS {
140- pending_edges. push ( ( rng. next_u32 ( ) , index, dim) )
141- }
142- }
143-
144- while let Some ( ( _, target_index, dim) ) = pending_edges. pop ( ) {
145- let a = unwrap_index ( lengths, target_index) . unwrap ( ) ;
146- if a[ dim] == lengths[ dim] {
147- continue ;
148- }
149- let mut b = a. clone ( ) ;
150- b[ dim] += 1 ;
151- if let Some ( cell_a) = cells. get ( & a) {
152- if let Some ( cell_b) = cells. get ( & b) {
153- if MazeGenCell :: try_merge ( cell_a, cell_b) {
154- maze. walks . insert ( ( a, b) ) ;
155- }
156- }
157- }
158- }
159-
160- maze
161- }
162-
163150#[ cfg( test) ]
164151mod tests {
165152 use super :: * ;
@@ -203,7 +190,7 @@ mod tests {
203190 #[ test]
204191 fn verify_generates ( ) {
205192 let mut rng = StdRng :: seed_from_u64 ( 684153987 ) ;
206- let maze = generate_maze ( & [ 5 , 5 , 5 , 5 , 5 ] , & mut rng) ;
193+ let maze = Maze :: new ( & [ 5 , 5 , 5 , 5 , 5 ] , & mut rng) ;
207194
208195 assert_eq ! (
209196 maze. can_move( & [ 1 , 2 , 3214 , 2 , 2 ] , 2 , MazeMoveDir :: Forward ) ,
@@ -214,7 +201,7 @@ mod tests {
214201 #[ test]
215202 fn verify_generates_single ( ) {
216203 let mut rng = StdRng :: seed_from_u64 ( 684153987 ) ;
217- let maze = generate_maze ( & [ 5 , 1 , 1 ] , & mut rng) ;
204+ let maze = Maze :: new ( & [ 5 , 1 , 1 ] , & mut rng) ;
218205
219206 assert_eq ! (
220207 maze. can_move( & [ 0 , 0 , 0 ] , 0 , MazeMoveDir :: Forward ) ,
0 commit comments