@@ -6,76 +6,107 @@ pub fn input_generator(input: &str) -> Input {
6
6
Grid :: from_input_chars ( input, |c, _, _| c as u8 )
7
7
}
8
8
9
- fn solve (
10
- input : & Input ,
11
- seen : & mut FxHashSet < ( usize , usize ) > ,
12
- ( x, y) : ( usize , usize ) ,
13
- d : usize ,
14
- ) -> usize {
15
- if y == input. h ( ) - 1 {
16
- return d;
17
- }
9
+ fn simplify_graph < const PART2 : bool > ( input : & Input ) -> Vec < ArrayVec < ( usize , usize ) , 4 > > {
10
+ let start = ( 0 ..input. w ( ) ) . find ( |& x| input[ ( x, 0 ) ] == b'.' ) ;
11
+ let end = ( 0 ..input. w ( ) ) . find ( |& x| input[ ( x, input. h ( ) - 1 ) ] == b'.' ) ;
12
+ let ( start, end) = ( start. unwrap ( ) , end. unwrap ( ) ) ;
13
+
14
+ let mut node_poss = vec ! [ ( start, 0 ) , ( end, input. h( ) - 1 ) ] ;
15
+ let mut node_edges = vec ! [ ArrayVec :: new( ) , ArrayVec :: new( ) ] ;
16
+ let mut pos_to_node = FxHashMap :: from_iter ( [ ( node_poss[ 0 ] , 0 ) , ( node_poss[ 1 ] , 1 ) ] ) ;
17
+ let mut explored = FxHashSet :: default ( ) ;
18
+ let mut to_visit = vec ! [ 0 ] ;
19
+
20
+ explored. reserve ( 128 ) ;
21
+ pos_to_node. reserve ( 64 ) ;
22
+
23
+ while let Some ( node) = to_visit. pop ( ) {
24
+ for ( mut x, mut y) in input. plus_neighbours ( node_poss[ node] ) {
25
+ if input[ ( x, y) ] == b'#' || !explored. insert ( ( x, y) ) {
26
+ continue ;
27
+ }
28
+
29
+ let mut d = 1 ;
30
+ let ( mut px, mut py) = node_poss[ node] ;
31
+ let ( mut forward, mut backward) = ( true , true ) ;
18
32
19
- let mut best = 0 ;
20
-
21
- for ( nx, ny) in input. plus_neighbours ( ( x, y) ) {
22
- if input[ ( nx, ny) ] != b'#' {
23
- let dx = ( nx as isize ) - ( x as isize ) ;
24
- let dy = ( ny as isize ) - ( y as isize ) ;
25
- match ( input[ ( nx, ny) ] , ( dx, dy) ) {
26
- ( b'<' , ( 1 , 0 ) ) => continue ,
27
- ( b'>' , ( -1 , 0 ) ) => continue ,
28
- ( b'v' , ( 0 , -1 ) ) => continue ,
29
- ( b'^' , ( 0 , 1 ) ) => continue ,
30
- _ => {
31
- if seen. insert ( ( nx, ny) ) {
32
- let nd = solve ( input, seen, ( nx, ny) , d + 1 ) ;
33
- best = max ( best, nd) ;
34
- seen. remove ( & ( nx, ny) ) ;
35
- }
33
+ loop {
34
+ let ( dx, dy) = ( x as isize - px as isize , y as isize - py as isize ) ;
35
+ match ( if PART2 { b'.' } else { input[ ( x, y) ] } , dx, dy) {
36
+ ( b'<' , 1 , 0 ) | ( b'>' , -1 , 0 ) | ( b'^' , 0 , 1 ) | ( b'v' , 0 , -1 ) => forward = false ,
37
+ ( b'<' , -1 , 0 ) | ( b'>' , 1 , 0 ) | ( b'^' , 0 , -1 ) | ( b'v' , 0 , 1 ) => backward = false ,
38
+ _ => { }
36
39
}
40
+
41
+ if ( x, y) == ( end, input. h ( ) - 1 ) {
42
+ node_edges[ node] . push ( ( 1 , d) ) ;
43
+ break ;
44
+ }
45
+
46
+ let mut iter = input
47
+ . plus_neighbours ( ( x, y) )
48
+ . filter ( |& ( nx, ny) | input[ ( nx, ny) ] != b'#' )
49
+ . filter ( |& ( nx, ny) | ( nx, ny) != ( px, py) ) ;
50
+
51
+ let Some ( ( nx, ny) ) = iter. next ( ) else { break } ;
52
+
53
+ if iter. next ( ) . is_some ( ) {
54
+ let end_node = * pos_to_node. entry ( ( x, y) ) . or_insert_with ( || {
55
+ let new_node = node_poss. len ( ) ;
56
+ node_poss. push ( ( x, y) ) ;
57
+ node_edges. push ( ArrayVec :: new ( ) ) ;
58
+ to_visit. push ( new_node) ;
59
+ new_node
60
+ } ) ;
61
+ explored. insert ( ( px, py) ) ;
62
+ forward. then ( || node_edges[ node] . push ( ( end_node, d) ) ) ;
63
+ backward. then ( || node_edges[ end_node] . push ( ( node, d) ) ) ;
64
+
65
+ break ;
66
+ }
67
+
68
+ ( px, py, x, y, d) = ( x, y, nx, ny, d + 1 ) ;
37
69
}
38
70
}
39
71
}
40
72
41
- best
73
+ node_edges
42
74
}
43
75
44
76
pub fn part1 ( input : & Input ) -> usize {
45
- let mut seen = FxHashSet :: default ( ) ;
46
- let start = ( 0 ..input. w ( ) ) . find ( |& x| input[ ( x, 0 ) ] == b'.' ) . unwrap ( ) ;
47
- solve ( input, & mut seen, ( start, 0 ) , 0 )
48
- }
49
-
50
- fn solve2 (
51
- input : & Input ,
52
- seen : & mut FxHashSet < ( usize , usize ) > ,
53
- ( x, y) : ( usize , usize ) ,
54
- d : usize ,
55
- ) -> usize {
56
- if y == input. h ( ) - 1 {
57
- return d;
77
+ fn solve ( edges : & [ ArrayVec < ( usize , usize ) , 4 > ] , seen : u64 , node : usize , d : usize ) -> usize {
78
+ edges[ node]
79
+ . iter ( )
80
+ . filter ( |& & ( next, _) | seen & ( 1 << next) == 0 )
81
+ . map ( |& ( next, cost) | solve ( edges, seen | ( 1 << next) , next, d + cost) )
82
+ . max ( )
83
+ . unwrap_or ( if node == 1 { d } else { 0 } )
58
84
}
85
+ solve ( & simplify_graph :: < false > ( input) , 0 , 0 , 0 )
86
+ }
59
87
60
- let mut best = 0 ;
88
+ pub fn part2 ( input : & Input ) -> usize {
89
+ fn solve ( edges : & [ ArrayVec < ( usize , usize ) , 4 > ] , seen : u64 , node : usize , d : usize ) -> usize {
90
+ let branches = edges[ node]
91
+ . iter ( )
92
+ . filter ( |& & ( next, _) | seen & ( 1 << next) == 0 )
93
+ . map ( |& ( next, cost) | move || solve ( edges, seen | ( 1 << next) , next, d + cost) )
94
+ . collect :: < ArrayVec < _ , 4 > > ( ) ;
61
95
62
- for ( nx, ny) in input. plus_neighbours ( ( x, y) ) {
63
- if input[ ( nx, ny) ] != b'#' {
64
- if seen. insert ( ( nx, ny) ) {
65
- stacker:: maybe_grow ( 32 * 1024 , 1024 * 1024 * 10 , || {
66
- let nd = solve2 ( input, seen, ( nx, ny) , d + 1 ) ;
67
- best = max ( best, nd) ;
68
- seen. remove ( & ( nx, ny) ) ;
69
- } ) ;
96
+ match & branches[ ..] {
97
+ & [ ] if node == 1 => d,
98
+ & [ ] => 0 ,
99
+ & [ f] => f ( ) ,
100
+ & [ f1, f2] => {
101
+ let ( d1, d2) = rayon:: join ( f1, f2) ;
102
+ max ( d1, d2)
70
103
}
104
+ & [ f1, f2, f3] => {
105
+ let ( d1, ( d2, d3) ) = rayon:: join ( f1, || rayon:: join ( f2, f3) ) ;
106
+ max ( d1, max ( d2, d3) )
107
+ }
108
+ _ => unreachable ! ( ) ,
71
109
}
72
110
}
73
-
74
- best
75
- }
76
-
77
- pub fn part2 ( input : & Input ) -> usize {
78
- let mut seen = FxHashSet :: default ( ) ;
79
- let start = ( 0 ..input. w ( ) ) . find ( |& x| input[ ( x, 0 ) ] == b'.' ) . unwrap ( ) ;
80
- solve2 ( input, & mut seen, ( start, 0 ) , 0 )
111
+ solve ( & simplify_graph :: < true > ( input) , 0 , 0 , 0 )
81
112
}
0 commit comments