@@ -7,9 +7,11 @@ use crate::utils::point::Point;
77use itertools:: Itertools ;
88use std:: collections:: HashMap ;
99use std:: fmt:: { Display , Formatter } ;
10+ use std:: iter:: repeat;
1011
1112type Positions = HashMap < u8 , Point > ;
1213type Adjacent = HashMap < Point , Vec < Point > > ;
14+ type Memo = HashMap < ( char , char , usize ) , String > ;
1315
1416const NUM_PAD : & str = r#"789
1517456
@@ -26,27 +28,33 @@ pub struct Day21;
2628
2729impl Solution for Day21 {
2830 fn part_one ( & self , input : & str ) -> String {
29- let pads = vec ! [ Pad :: numeric( ) , Pad :: key( ) , Pad :: key( ) ] ;
31+ self . solve ( input, 2 ) . to_string ( )
32+ }
33+
34+ fn part_two ( & self , input : & str ) -> String {
35+ self . solve ( input, 25 ) . to_string ( )
36+ }
37+ }
38+
39+ impl Day21 {
40+ fn solve ( & self , input : & str , keypad_count : usize ) -> usize {
41+ let mut pads = vec ! [ Pad :: numeric( ) ] ;
42+ let mut memo = Memo :: new ( ) ;
43+
44+ pads. extend ( repeat ( Pad :: key ( ) ) . take ( keypad_count) ) ;
3045
3146 input
3247 . lines ( )
3348 . map ( |line| {
34- let path_len = self . path ( line, & pads) . chars ( ) . count ( ) ;
49+ let path_len = self . path ( line, & pads, & mut memo ) . chars ( ) . count ( ) ;
3550 let num: usize = line. trim_end_matches ( 'A' ) . parse ( ) . unwrap ( ) ;
3651
3752 num * path_len
3853 } )
3954 . sum :: < usize > ( )
40- . to_string ( )
4155 }
4256
43- fn part_two ( & self , _input : & str ) -> String {
44- String :: from ( '0' )
45- }
46- }
47-
48- impl Day21 {
49- fn path ( & self , code : & str , pads : & [ Pad ] ) -> String {
57+ fn path ( & self , code : & str , pads : & [ Pad ] , memo : & mut Memo ) -> String {
5058 if pads. is_empty ( ) {
5159 return code. to_string ( ) ;
5260 }
@@ -58,11 +66,20 @@ impl Day21 {
5866 code. chars ( )
5967 . tuple_windows ( )
6068 . map ( |( from, to) | {
61- self . all_shortest_paths_between_buttons ( from, to, pad)
69+ if let Some ( path) = memo. get ( & ( from, to, pad_left. len ( ) ) ) {
70+ return path. clone ( ) ;
71+ }
72+
73+ let shortest_path = self
74+ . all_shortest_paths_between_buttons ( from, to, pad)
6275 . iter ( )
63- . map ( |path| self . path ( path, pad_left) )
76+ . map ( |path| self . path ( path, pad_left, memo ) )
6477 . min_by_key ( |path| path. chars ( ) . count ( ) )
65- . unwrap ( )
78+ . unwrap ( ) ;
79+
80+ memo. insert ( ( from, to, pad_left. len ( ) ) , shortest_path. clone ( ) ) ;
81+
82+ shortest_path
6683 } )
6784 . collect ( )
6885 }
@@ -121,6 +138,7 @@ impl Display for Key {
121138 }
122139}
123140
141+ #[ derive( Clone ) ]
124142struct Pad {
125143 positions : Positions ,
126144 adjacent : Adjacent ,
@@ -182,7 +200,7 @@ impl Pad {
182200
183201#[ cfg( test) ]
184202mod tests {
185- use crate :: solutions:: year2024:: day21:: { Day21 , Pad } ;
203+ use crate :: solutions:: year2024:: day21:: { Day21 , Memo , Pad } ;
186204 use crate :: solutions:: Solution ;
187205
188206 const EXAMPLE : & str = r#"029A
@@ -199,12 +217,13 @@ mod tests {
199217 #[ test]
200218 fn path_len ( ) {
201219 let pads = vec ! [ Pad :: numeric( ) , Pad :: key( ) , Pad :: key( ) ] ;
202-
203- assert_eq ! ( 68 , Day21 . path( "029A" , & pads) . len( ) ) ;
204- assert_eq ! ( 60 , Day21 . path( "980A" , & pads) . len( ) ) ;
205- assert_eq ! ( 68 , Day21 . path( "179A" , & pads) . len( ) ) ;
206- assert_eq ! ( 64 , Day21 . path( "456A" , & pads) . len( ) ) ;
207- assert_eq ! ( 64 , Day21 . path( "379A" , & pads) . len( ) ) ;
208- assert_eq ! ( 78 , Day21 . path( "739A" , & pads) . len( ) ) ;
220+ let mut memo = Memo :: new ( ) ;
221+
222+ assert_eq ! ( 68 , Day21 . path( "029A" , & pads, & mut memo) . len( ) ) ;
223+ assert_eq ! ( 60 , Day21 . path( "980A" , & pads, & mut memo) . len( ) ) ;
224+ assert_eq ! ( 68 , Day21 . path( "179A" , & pads, & mut memo) . len( ) ) ;
225+ assert_eq ! ( 64 , Day21 . path( "456A" , & pads, & mut memo) . len( ) ) ;
226+ assert_eq ! ( 64 , Day21 . path( "379A" , & pads, & mut memo) . len( ) ) ;
227+ assert_eq ! ( 78 , Day21 . path( "739A" , & pads, & mut memo) . len( ) ) ;
209228 }
210229}
0 commit comments