44//! [BFS](https://en.wikipedia.org/wiki/Breadth-first_search) solving both part one and part
55//! two simultaneously.
66//!
7- //! As we start at (1, 1) and the most steps that we are interested in is 50, we can bound
8- //! the maze to 2 + 50 = 52 in each dimension and used a fixed size array.
7+ //! As we start at (1, 1) and the most steps that we are interested in for part 2 is 50, while
8+ //! part 1 requires more than 50 steps but should easily be reachable without exceeding bounds,
9+ //! we can bound the maze to 2 + 50 = 52 in each dimension and use a fixed size array. Rather
10+ //! than filling the array up front, we can lazily populate it as the horizon expands.
911
1012use crate :: util:: parse:: * ;
1113use std:: collections:: VecDeque ;
@@ -14,49 +16,47 @@ type Input = (u32, u32);
1416
1517pub fn parse ( input : & str ) -> Input {
1618 let favorite: usize = input. unsigned ( ) ;
17- let mut maze = [ [ false ; 52 ] ; 52 ] ;
1819
19- for ( x, row) in maze. iter_mut ( ) . enumerate ( ) {
20- for ( y, cell) in row. iter_mut ( ) . enumerate ( ) {
21- let n = ( x * x) + ( 3 * x) + ( 2 * x * y) + y + ( y * y) + favorite;
22- * cell = n. count_ones ( ) . is_multiple_of ( 2 ) ;
20+ // Lazy evaluation: set maze[x][y] to true once a point is visited
21+ let mut maze = [ [ false ; 52 ] ; 52 ] ;
22+ maze[ 1 ] [ 1 ] = true ;
23+ let mut at = |x : usize , y : usize | -> bool {
24+ if maze[ x] [ y] {
25+ return false ;
2326 }
24- }
27+ maze[ x] [ y] = true ;
28+ let n = ( x * x) + ( 3 * x) + ( 2 * x * y) + y + ( y * y) + favorite;
29+ n. count_ones ( ) . is_multiple_of ( 2 )
30+ } ;
2531
26- let mut part_one = 0 ;
2732 let mut part_two = 0 ;
2833 let mut todo = VecDeque :: new ( ) ;
2934
3035 todo. push_back ( ( 1 , 1 , 0 ) ) ;
31- maze[ 1 ] [ 1 ] = false ;
3236
3337 while let Some ( ( x, y, cost) ) = todo. pop_front ( ) {
3438 if x == 31 && y == 39 {
35- part_one = cost;
39+ return ( cost, part_two ) ;
3640 }
3741 if cost <= 50 {
3842 part_two += 1 ;
3943 }
4044
41- if x > 0 && maze [ x - 1 ] [ y ] {
45+ if x > 0 && at ( x - 1 , y ) {
4246 todo. push_back ( ( x - 1 , y, cost + 1 ) ) ;
43- maze[ x - 1 ] [ y] = false ;
4447 }
45- if y > 0 && maze [ x ] [ y - 1 ] {
48+ if y > 0 && at ( x , y - 1 ) {
4649 todo. push_back ( ( x, y - 1 , cost + 1 ) ) ;
47- maze[ x] [ y - 1 ] = false ;
4850 }
49- if x < 51 && maze [ x + 1 ] [ y ] {
51+ if at ( x + 1 , y ) {
5052 todo. push_back ( ( x + 1 , y, cost + 1 ) ) ;
51- maze[ x + 1 ] [ y] = false ;
5253 }
53- if y < 51 && maze [ x ] [ y + 1 ] {
54+ if at ( x , y + 1 ) {
5455 todo. push_back ( ( x, y + 1 , cost + 1 ) ) ;
55- maze[ x] [ y + 1 ] = false ;
5656 }
5757 }
5858
59- ( part_one , part_two )
59+ unreachable ! ( ) ;
6060}
6161
6262pub fn part1 ( input : & Input ) -> u32 {
0 commit comments