1- use std:: { collections:: HashMap , fs, hash:: Hash , ops:: AddAssign } ;
1+ use std:: { collections:: HashMap , fs, hash:: Hash , num :: ParseIntError , ops:: AddAssign , str :: FromStr } ;
22
33pub fn day11 ( input_path : String ) {
44 let content = fs:: read_to_string ( input_path) . unwrap ( ) ;
55
6- let stones: Vec < _ > = content. split_whitespace ( ) . map ( Stone :: parse) . collect ( ) ;
6+ let stones: Vec < _ > = content
7+ . split_whitespace ( )
8+ . map ( |l| l. parse ( ) . unwrap ( ) )
9+ . collect ( ) ;
710
811 println ! ( "{:?}" , part1( stones. iter( ) . cloned( ) . collect( ) ) ) ;
9- println ! ( "{:?}" , part2( stones) ) ;
12+ println ! ( "{:?}" , part2( & stones) ) ;
13+
14+
15+ let stones: Vec < _ > = content
16+ . split_whitespace ( )
17+ . map ( |l| l. parse ( ) . unwrap ( ) ) // this deduces Stone2 because of the signature of part12
18+ . collect ( ) ;
19+
20+ println ! ( "{:?}" , part12( & stones) ) ;
21+ println ! ( "{:?}" , part22( & stones) ) ;
1022}
1123
1224// Most significant digit is last,
@@ -24,12 +36,12 @@ fn part1(stones: Vec<Stone>) -> usize {
2436 . len ( )
2537}
2638
27- fn part2 ( stones : Vec < Stone > ) -> usize {
28- let mut stone_map : HashMap < Stone , usize > =
29- accumulate_into_hashmap ( stones. into_iter ( ) . map ( |s| ( s, 1 ) ) ) ;
39+ fn part2 ( stones : & [ Stone ] ) -> usize {
40+ // order does not matter, so we can compress the stones into a hashmap, and do every operation just once
41+ let mut stone_map : HashMap < Stone , usize > = accumulate ( stones. iter ( ) . map ( |s| ( s. clone ( ) , 1 ) ) ) ;
3042
3143 for _ in 0 ..75 {
32- stone_map = accumulate_into_hashmap (
44+ stone_map = accumulate (
3345 stone_map
3446 . into_iter ( )
3547 . flat_map ( |( stone, count) | blink_at ( stone) . into_iter ( ) . map ( move |s| ( s, count) ) ) ,
@@ -38,20 +50,6 @@ fn part2(stones: Vec<Stone>) -> usize {
3850 stone_map. iter ( ) . map ( |( _, count) | count) . sum ( )
3951}
4052
41- fn accumulate_into_hashmap < T , N , I > ( values : I ) -> HashMap < T , N >
42- where
43- T : Eq + Hash ,
44- N : Default + AddAssign ,
45- I : IntoIterator < Item = ( T , N ) > ,
46- {
47- values
48- . into_iter ( )
49- . fold ( HashMap :: new ( ) , |mut acc, ( key, value) | {
50- * acc. entry ( key) . or_default ( ) += value;
51- acc
52- } )
53- }
54-
5553fn blink_at ( stone : Stone ) -> Vec < Stone > {
5654 match stone {
5755 zero if zero. 0 . is_empty ( ) => vec ! [ Stone :: from( [ 1 ] ) ] ,
@@ -61,17 +59,6 @@ fn blink_at(stone: Stone) -> Vec<Stone> {
6159}
6260
6361impl Stone {
64- // should actually be proper parse
65- fn parse ( string : & str ) -> Stone {
66- Stone :: new (
67- string
68- . chars ( )
69- . map ( |c| c. to_digit ( 10 ) . unwrap ( ) as u8 )
70- . rev ( )
71- . collect ( ) ,
72- )
73- }
74-
7562 fn new ( digits : Vec < u8 > ) -> Stone {
7663 Stone ( digits) . trimmed ( )
7764 }
@@ -108,29 +95,208 @@ impl Stone {
10895 }
10996}
11097
98+ #[ derive( Debug , PartialEq , Eq ) ]
99+ struct ParseStoneError ;
100+
101+ impl FromStr for Stone {
102+ type Err = ParseStoneError ;
103+
104+ // this is just for illustrating
105+ // fn from_str(s: &str) -> Result<Self, Self::Err> {
106+ // let digits: Result<Vec<u8>, ParseStoneError> = s
107+ // .chars()
108+ // .map(|c| c.to_digit(10).map(|d| d as u8).ok_or(ParseStoneError))
109+ // .rev()
110+ // // this collect flips and creates a vector,
111+ // // i.e. it does
112+ // // Iter<Result<u8, Error>> -> Result<Vec<u8>, Error>
113+ // // i.e. it does "early return with Result"
114+ // .collect();
115+ // Ok(Stone::new(digits?))
116+ // }
117+
118+ fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
119+ s. chars ( )
120+ . map ( |c| c. to_digit ( 10 ) . map ( |d| d as u8 ) . ok_or ( ParseStoneError ) )
121+ . rev ( )
122+ . collect :: < Result < _ , _ > > ( )
123+ . map ( Stone :: new)
124+ }
125+ }
126+
127+ fn accumulate < T , N , I > ( values : I ) -> HashMap < T , N >
128+ where
129+ T : Eq + Hash ,
130+ N : Default + AddAssign ,
131+ I : IntoIterator < Item = ( T , N ) > ,
132+ {
133+ values
134+ . into_iter ( )
135+ . fold ( HashMap :: new ( ) , |mut acc, ( key, value) | {
136+ * acc. entry ( key) . or_default ( ) += value;
137+ acc
138+ } )
139+ }
140+
141+ #[ derive( Debug , PartialEq , Eq , Clone , Hash ) ]
142+ struct Stone2 {
143+ number : usize ,
144+ digits : u32 ,
145+ }
146+
147+ fn digits ( number : usize ) -> u32 {
148+ if number == 0 {
149+ return 1 ;
150+ }
151+ let mut temp = number;
152+ let mut digit_count = 0 ;
153+ while temp > 0 {
154+ temp /= 10 ;
155+ digit_count += 1 ;
156+ }
157+ digit_count
158+ }
159+
160+ impl Stone2 {
161+ fn new ( number : usize ) -> Self {
162+ Stone2 {
163+ number,
164+ digits : digits ( number) ,
165+ }
166+ }
167+
168+ fn split ( self ) -> [ Self ; 2 ] {
169+ // calling this with odd number of digits is ub (I'm lazy)
170+ let divisor = 10usize . pow ( self . digits / 2 ) ;
171+ let left = Stone2 {
172+ number : self . number / divisor,
173+ digits : self . digits / 2 ,
174+ } ;
175+ // right could have leading zeros, recompute digits
176+ let right = Stone2 :: new ( self . number % divisor) ;
177+ [ left, right]
178+ }
179+
180+ fn muled_by ( self , n : usize ) -> Self {
181+ Stone2 :: new ( self . number * n)
182+ }
183+ }
184+
185+ // here, returning impl Iterator<Item = Stone2>
186+ // does not work, because all match arms would need to have the same concrete type
187+ // (which they cannot have, except when we'd implement a bespoke OneOrTwo-struct)
188+ fn blink_at2 ( stone : Stone2 ) -> Vec < Stone2 > {
189+ match stone {
190+ Stone2 {
191+ number : 0 ,
192+ digits : 1 ,
193+ } => vec ! [ Stone2 {
194+ number: 1 ,
195+ digits: 1 ,
196+ } ] ,
197+ even if even. digits % 2 == 0 => Vec :: from ( even. split ( ) ) ,
198+ other => vec ! [ other. muled_by( 2024 ) ] ,
199+ }
200+ }
201+
202+ fn do_rounds ( stones : & [ Stone2 ] , rounds : usize ) -> usize {
203+ let mut stone_map = accumulate ( stones. iter ( ) . map ( |s| ( s. clone ( ) , 1 ) ) ) ;
204+
205+ for _ in 0 ..rounds {
206+ stone_map = accumulate (
207+ stone_map
208+ . into_iter ( )
209+ . flat_map ( |( stone, count) | blink_at2 ( stone) . into_iter ( ) . map ( move |s| ( s, count) ) ) ,
210+ ) ;
211+ }
212+ stone_map. iter ( ) . map ( |( _, count) | count) . sum ( )
213+ }
214+
215+ fn part12 ( stones : & [ Stone2 ] ) -> usize {
216+ do_rounds ( stones, 25 )
217+ }
218+
219+ fn part22 ( stones : & [ Stone2 ] ) -> usize {
220+ do_rounds ( stones, 75 )
221+ }
222+
223+ impl FromStr for Stone2 {
224+ type Err = ParseIntError ;
225+
226+ fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
227+ s. parse ( ) . map ( |ds| Stone2 :: new ( ds) )
228+ }
229+ }
230+
111231#[ cfg( test) ]
112232mod tests {
113233 use super :: * ;
114234
115235 #[ test]
116236 fn test_muled_by_zero ( ) {
117- let stone = Stone :: parse ( "123" ) ;
237+ let stone: Stone = "123" . parse ( ) . unwrap ( ) ;
118238 let result = stone. muled_by ( 0 ) ;
119239 assert_eq ! ( result. 0 , vec![ 0 , 0 , 0 ] ) ; // 123 * 0 = 0
120240 }
121241
122242 #[ test]
123243 fn test_muled_by_one ( ) {
124- let stone = Stone :: parse ( "456" ) ;
244+ let stone: Stone = "456" . parse ( ) . unwrap ( ) ;
125245 let result = stone. muled_by ( 1 ) ;
126246 assert_eq ! ( result. 0 , vec![ 6 , 5 , 4 ] ) ; // 456 * 1 = 456
127247 }
128248
129249 #[ test]
130250 fn test_muled_by_large_number ( ) {
131- let stone = Stone :: parse ( "999" ) ;
251+ let stone: Stone = "999" . parse ( ) . unwrap ( ) ;
132252 let result = stone. muled_by ( 999 ) ;
133253 // 999 * 999 = 998001
134254 assert_eq ! ( result. 0 , vec![ 1 , 0 , 0 , 8 , 9 , 9 ] ) ;
135255 }
256+
257+ #[ test]
258+ fn test_muled_by_zero2 ( ) {
259+ let stone: Stone2 = "123" . parse ( ) . unwrap ( ) ;
260+ let result = stone. muled_by ( 0 ) ;
261+ assert_eq ! (
262+ result,
263+ Stone2 {
264+ number: 0 ,
265+ digits: 1
266+ }
267+ ) ; // 123 * 0 = 0
268+ }
269+
270+ #[ test]
271+ fn test_muled_by_one2 ( ) {
272+ let stone: Stone2 = "456" . parse ( ) . unwrap ( ) ;
273+ let result = stone. muled_by ( 1 ) ;
274+ assert_eq ! (
275+ result,
276+ Stone2 {
277+ number: 456 ,
278+ digits: 3
279+ }
280+ ) ; // 456 * 1 = 456
281+ }
282+
283+ #[ test]
284+ fn test_muled_by_large_number2 ( ) {
285+ let stone: Stone2 = "999" . parse ( ) . unwrap ( ) ;
286+ let result = stone. muled_by ( 999 ) ;
287+ assert_eq ! (
288+ result,
289+ Stone2 {
290+ number: 998001 ,
291+ digits: 6
292+ }
293+ ) ; // 999 * 999 = 998001
294+ }
295+
296+ #[ test]
297+ fn test_split ( ) {
298+ let stone: Stone2 = "1001" . parse ( ) . unwrap ( ) ;
299+ let result = stone. split ( ) ;
300+ assert_eq ! ( result, [ Stone2 :: new( 10 ) , Stone2 :: new( 1 ) ] ) ;
301+ }
136302}
0 commit comments