@@ -2,87 +2,81 @@ use std::collections::HashMap;
22
33use common:: { Answer , solution} ;
44
5+ type Graph < ' a > = HashMap < & ' a str , Vec < & ' a str > > ;
6+
57solution ! ( "Reactor" , 11 ) ;
68
79fn 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 {
10+ fn count_paths ( map : & Graph , current : & str ) -> u64 {
1711 if current == "out" {
1812 return 1 ;
1913 }
2014
21- let mut out = 0 ;
22-
23- for child in & map[ current] {
24- out += count_paths ( map, child) ;
25- }
26-
27- out
15+ ( map[ current] . iter ( ) )
16+ . map ( |child| count_paths ( map, child) )
17+ . sum ( )
2818 }
2919
30- count_paths ( & map , "you" ) . into ( )
20+ count_paths ( & parse ( input ) , "you" ) . into ( )
3121}
3222
3323fn part_b ( input : & str ) -> Answer {
34- let mut map = HashMap :: new ( ) ;
35-
36- for line in input. lines ( ) {
37- let ( from, to) = line. split_once ( ": " ) . unwrap ( ) ;
38- let to = to. split_whitespace ( ) . collect :: < Vec < _ > > ( ) ;
39- map. insert ( from, to) ;
40- }
41-
4224 fn count_paths < ' a > (
43- memo : & mut HashMap < ( & ' a str , bool , bool ) , u64 > ,
44- map : & HashMap < & str , Vec < & ' a str > > ,
25+ memo : & mut HashMap < ( & ' a str , ( bool , bool ) ) , u64 > ,
26+ map : & Graph < ' a > ,
4527 current : & ' a str ,
46- mut fft : bool ,
47- mut dac : bool ,
28+ ( fft, dac) : ( bool , bool ) ,
4829 ) -> u64 {
49- let key = ( current, fft, dac) ;
50- if let Some ( memo) = memo. get ( & key ) {
30+ let entry = ( current, ( fft, dac) ) ;
31+ if let Some ( memo) = memo. get ( & entry ) {
5132 return * memo;
5233 }
5334
5435 if current == "out" {
55- if fft && dac {
56- return 1 ;
57- }
58- return 0 ;
36+ return ( fft && dac) as u64 ;
5937 }
6038
61- if current == "fft" {
62- fft = true ;
63- }
39+ let seen = ( fft || current == "fft" , dac || current == "dac" ) ;
40+ let out = ( map[ current] . iter ( ) )
41+ . map ( |child| count_paths ( memo, map, child, seen) )
42+ . sum ( ) ;
6443
65- if current == "dac" {
66- dac = true ;
67- }
44+ memo . insert ( entry , out ) ;
45+ out
46+ }
6847
69- let mut out = 0 ;
70- for child in & map[ current] {
71- out += count_paths ( memo, map, child, fft, dac) ;
72- }
48+ count_paths ( & mut HashMap :: new ( ) , & parse ( input) , "svr" , ( false , false ) ) . into ( )
49+ }
7350
74- memo. insert ( key, out) ;
75- out
51+ fn parse ( input : & str ) -> HashMap < & str , Vec < & str > > {
52+ let mut map = HashMap :: new ( ) ;
53+ for line in input. lines ( ) {
54+ let ( from, to) = line. split_once ( ": " ) . unwrap ( ) ;
55+ let to = to. split_whitespace ( ) . collect :: < Vec < _ > > ( ) ;
56+ map. insert ( from, to) ;
7657 }
7758
78- count_paths ( & mut HashMap :: new ( ) , & map, "svr" , false , false ) . into ( )
59+ map
7960}
8061
8162#[ cfg( test) ]
8263mod test {
8364 use indoc:: indoc;
8465
85- const CASE : & str = indoc ! { "
66+ const CASE_A : & str = indoc ! { "
67+ aaa: you hhh
68+ you: bbb ccc
69+ bbb: ddd eee
70+ ccc: ddd eee fff
71+ ddd: ggg
72+ eee: out
73+ fff: out
74+ ggg: out
75+ hhh: ccc fff iii
76+ iii: out
77+ " } ;
78+
79+ const CASE_B : & str = indoc ! { "
8680 svr: aaa bbb
8781 aaa: fft
8882 fft: ccc
@@ -100,11 +94,11 @@ mod test {
10094
10195 #[ test]
10296 fn part_a ( ) {
103- assert_eq ! ( super :: part_a( CASE ) , 5 . into( ) ) ;
97+ assert_eq ! ( super :: part_a( CASE_A ) , 5 . into( ) ) ;
10498 }
10599
106100 #[ test]
107101 fn part_b ( ) {
108- assert_eq ! ( super :: part_b( CASE ) , 2 . into( ) ) ;
102+ assert_eq ! ( super :: part_b( CASE_B ) , 2 . into( ) ) ;
109103 }
110104}
0 commit comments