@@ -5,84 +5,66 @@ use common::{Answer, solution};
55solution ! ( "Reactor" , 11 ) ;
66
77fn part_a ( input : & str ) -> Answer {
8- let mut map = HashMap :: new ( ) ;
9-
10- for line in input. lines ( ) {
11- let ( from, to) = line. split_once ( ": " ) . unwrap ( ) ;
12- let to = to. split_whitespace ( ) . collect :: < Vec < _ > > ( ) ;
13- map. insert ( from, to) ;
14- }
15-
16- fn count_paths ( map : & HashMap < & str , Vec < & str > > , current : & str ) -> u64 {
17- if current == "out" {
18- return 1 ;
19- }
8+ count_paths ( & mut HashMap :: new ( ) , & parse ( input) , "you" , [ true ; _] ) . into ( )
9+ }
2010
21- let mut out = 0 ;
11+ fn part_b ( input : & str ) -> Answer {
12+ count_paths ( & mut HashMap :: new ( ) , & parse ( input) , "svr" , [ false ; _] ) . into ( )
13+ }
2214
23- for child in & map[ current] {
24- out += count_paths ( map, child) ;
25- }
15+ fn count_paths < ' a > (
16+ memo : & mut HashMap < ( & ' a str , [ bool ; 2 ] ) , u64 > ,
17+ map : & HashMap < & ' a str , Vec < & ' a str > > ,
18+ current : & ' a str ,
19+ seen @ [ fft, dac] : [ bool ; 2 ] ,
20+ ) -> u64 {
21+ let entry = ( current, seen) ;
22+ if let Some ( memo) = memo. get ( & entry) {
23+ return * memo;
24+ }
2625
27- out
26+ if current == "out" {
27+ return ( fft && dac) as u64 ;
2828 }
2929
30- count_paths ( & map, "you" ) . into ( )
30+ let seen = [ fft || current == "fft" , dac || current == "dac" ] ;
31+ let out = ( map[ current] . iter ( ) )
32+ . map ( |child| count_paths ( memo, map, child, seen) )
33+ . sum ( ) ;
34+
35+ memo. insert ( entry, out) ;
36+ out
3137}
3238
33- fn part_b ( input : & str ) -> Answer {
39+ fn parse ( input : & str ) -> HashMap < & str , Vec < & str > > {
3440 let mut map = HashMap :: new ( ) ;
35-
3641 for line in input. lines ( ) {
3742 let ( from, to) = line. split_once ( ": " ) . unwrap ( ) ;
3843 let to = to. split_whitespace ( ) . collect :: < Vec < _ > > ( ) ;
3944 map. insert ( from, to) ;
4045 }
4146
42- fn count_paths < ' a > (
43- memo : & mut HashMap < ( & ' a str , bool , bool ) , u64 > ,
44- map : & HashMap < & str , Vec < & ' a str > > ,
45- current : & ' a str ,
46- mut fft : bool ,
47- mut dac : bool ,
48- ) -> u64 {
49- let key = ( current, fft, dac) ;
50- if let Some ( memo) = memo. get ( & key) {
51- return * memo;
52- }
53-
54- if current == "out" {
55- if fft && dac {
56- return 1 ;
57- }
58- return 0 ;
59- }
60-
61- if current == "fft" {
62- fft = true ;
63- }
64-
65- if current == "dac" {
66- dac = true ;
67- }
68-
69- let mut out = 0 ;
70- for child in & map[ current] {
71- out += count_paths ( memo, map, child, fft, dac) ;
72- }
73-
74- memo. insert ( key, out) ;
75- out
76- }
77-
78- count_paths ( & mut HashMap :: new ( ) , & map, "svr" , false , false ) . into ( )
47+ map
7948}
8049
8150#[ cfg( test) ]
8251mod test {
8352 use indoc:: indoc;
8453
85- const CASE : & str = indoc ! { "
54+ const CASE_A : & str = indoc ! { "
55+ aaa: you hhh
56+ you: bbb ccc
57+ bbb: ddd eee
58+ ccc: ddd eee fff
59+ ddd: ggg
60+ eee: out
61+ fff: out
62+ ggg: out
63+ hhh: ccc fff iii
64+ iii: out
65+ " } ;
66+
67+ const CASE_B : & str = indoc ! { "
8668 svr: aaa bbb
8769 aaa: fft
8870 fft: ccc
@@ -100,11 +82,11 @@ mod test {
10082
10183 #[ test]
10284 fn part_a ( ) {
103- assert_eq ! ( super :: part_a( CASE ) , 5 . into( ) ) ;
85+ assert_eq ! ( super :: part_a( CASE_A ) , 5 . into( ) ) ;
10486 }
10587
10688 #[ test]
10789 fn part_b ( ) {
108- assert_eq ! ( super :: part_b( CASE ) , 2 . into( ) ) ;
90+ assert_eq ! ( super :: part_b( CASE_B ) , 2 . into( ) ) ;
10991 }
11092}
0 commit comments