@@ -23,8 +23,55 @@ impl Solution for Day09 {
2323 disk_map. checksum ( ) . to_string ( )
2424 }
2525
26- fn part_two ( & self , _input : & str ) -> String {
27- String :: from ( '0' )
26+ fn part_two ( & self , input : & str ) -> String {
27+ let mut block_disk_map = BlockDiskMap :: from_str ( input) . unwrap ( ) ;
28+ let mut last_checked_index = usize:: MAX ;
29+
30+ loop {
31+ let cloned = block_disk_map. blocks . clone ( ) ;
32+ let last_filled_block = cloned. iter ( ) . enumerate ( ) . rfind ( |( i, block) | {
33+ last_checked_index > * i && matches ! ( block, Block :: Filled { .. } )
34+ } ) ;
35+
36+ if last_filled_block. is_none ( ) {
37+ break ;
38+ }
39+
40+ let filled_unwrapped = last_filled_block. unwrap ( ) ;
41+ last_checked_index = filled_unwrapped. 0 ;
42+
43+ let cloned = block_disk_map. blocks . clone ( ) ;
44+ let first_matching_spot =
45+ cloned
46+ . iter ( )
47+ . enumerate ( )
48+ . find ( |( empty_index, block) | match block {
49+ Block :: Empty { size } => {
50+ empty_index < & filled_unwrapped. 0 && size >= & filled_unwrapped. 1 . size ( )
51+ }
52+ _ => false ,
53+ } ) ;
54+
55+ if first_matching_spot. is_none ( ) {
56+ continue ;
57+ }
58+
59+ let ( empty_index, matching_block) = first_matching_spot. unwrap ( ) ;
60+ let ( filled_index, filled_block) = last_filled_block. unwrap ( ) ;
61+
62+ let split = matching_block. split ( filled_block) ;
63+
64+ block_disk_map. blocks [ filled_index] = Block :: Empty {
65+ size : filled_block. size ( ) ,
66+ } ;
67+ block_disk_map. blocks . remove ( empty_index) ;
68+
69+ for ( i, block) in split. iter ( ) . enumerate ( ) {
70+ block_disk_map. blocks . insert ( empty_index + i, block. clone ( ) ) ;
71+ }
72+ }
73+
74+ Into :: < DiskMap > :: into ( block_disk_map) . checksum ( ) . to_string ( )
2875 }
2976}
3077
@@ -36,20 +83,25 @@ impl DiskMap {
3683 fn checksum ( & self ) -> usize {
3784 self . blocks
3885 . clone ( )
39- . into_iter ( )
40- . flatten ( )
86+ . iter ( )
4187 . enumerate ( )
42- . fold ( 0 , |acc, ( i, id) | acc + i * id)
88+ . fold ( 0 , |acc, ( i, id) | {
89+ if let Some ( id) = id {
90+ return acc + i * id;
91+ }
92+
93+ acc
94+ } )
4395 }
4496}
4597
4698impl FromStr for DiskMap {
47- type Err = String ;
99+ type Err = ( ) ;
48100
49101 fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
50102 let mut current_id = 0 ;
51103
52- let test : Vec < Option < usize > > = s
104+ let blocks : Vec < Option < usize > > = s
53105 . trim ( )
54106 . chars ( )
55107 . enumerate ( )
@@ -74,7 +126,7 @@ impl FromStr for DiskMap {
74126 } )
75127 . collect ( ) ;
76128
77- Ok ( Self { blocks : test } )
129+ Ok ( Self { blocks } )
78130 }
79131}
80132
@@ -93,9 +145,115 @@ impl Display for DiskMap {
93145 }
94146}
95147
148+ impl From < BlockDiskMap > for DiskMap {
149+ fn from ( value : BlockDiskMap ) -> Self {
150+ let blocks = value
151+ . blocks
152+ . into_iter ( )
153+ . flat_map ( |v| match v {
154+ Block :: Empty { size } => vec ! [ None ; size] ,
155+ Block :: Filled { size, id } => vec ! [ Some ( id) ; size] ,
156+ } )
157+ . collect ( ) ;
158+
159+ Self { blocks }
160+ }
161+ }
162+
163+ #[ derive( Debug , PartialEq , Clone ) ]
164+ enum Block {
165+ Empty { size : usize } ,
166+ Filled { size : usize , id : usize } ,
167+ }
168+
169+ impl Block {
170+ fn size ( & self ) -> usize {
171+ match self {
172+ Block :: Empty { size } => size. to_owned ( ) ,
173+ Block :: Filled { size, .. } => size. to_owned ( ) ,
174+ }
175+ }
176+
177+ fn split ( & self , other : & Self ) -> Vec < Self > {
178+ match ( self , other) {
179+ (
180+ Block :: Empty { size } ,
181+ Block :: Filled {
182+ size : filled_size,
183+ id,
184+ } ,
185+ ) => {
186+ if filled_size > size {
187+ panic ! ( "filled size cannot be greater than empty" ) ;
188+ }
189+
190+ if filled_size == size {
191+ return vec ! [ Block :: Filled {
192+ size: * filled_size,
193+ id: * id,
194+ } ] ;
195+ }
196+
197+ if filled_size < size {
198+ return vec ! [
199+ Block :: Filled {
200+ size: * filled_size,
201+ id: * id,
202+ } ,
203+ Block :: Empty {
204+ size: size - filled_size,
205+ } ,
206+ ] ;
207+ }
208+
209+ unreachable ! ( )
210+ }
211+ ( _, _) => panic ! ( "illegal block" ) ,
212+ }
213+ }
214+ }
215+
216+ #[ derive( Debug , PartialEq , Clone ) ]
217+ struct BlockDiskMap {
218+ blocks : Vec < Block > ,
219+ }
220+
221+ impl FromStr for BlockDiskMap {
222+ type Err = ( ) ;
223+
224+ fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
225+ let mut current_id = 0 ;
226+
227+ let blocks: Vec < Block > = s
228+ . trim ( )
229+ . chars ( )
230+ . enumerate ( )
231+ . map ( |( i, c) | {
232+ let size: usize = c
233+ . to_string ( )
234+ . parse ( )
235+ . unwrap_or_else ( |_| panic ! ( "cannot parse char to usize: '{}'" , c) ) ;
236+
237+ match i % 2 == 0 {
238+ true => {
239+ let id = current_id;
240+
241+ current_id += 1 ;
242+
243+ Block :: Filled { size, id }
244+ }
245+ false => Block :: Empty { size } ,
246+ }
247+ } )
248+ . collect ( ) ;
249+
250+ Ok ( Self { blocks } )
251+ }
252+ }
253+
96254#[ cfg( test) ]
97255mod tests {
98- use crate :: solutions:: year2024:: day09:: { Day09 , DiskMap } ;
256+ use crate :: solutions:: year2024:: day09:: { Block , BlockDiskMap , Day09 , DiskMap } ;
99257 use crate :: solutions:: Solution ;
100258 use std:: str:: FromStr ;
101259
@@ -107,7 +265,12 @@ mod tests {
107265 }
108266
109267 #[ test]
110- fn parse_test ( ) {
268+ fn part_two_example_test ( ) {
269+ assert_eq ! ( "2858" , Day09 . part_two( EXAMPLE ) ) ;
270+ }
271+
272+ #[ test]
273+ fn disk_map_parse_test ( ) {
111274 let result = DiskMap :: from_str ( "12345" ) . unwrap ( ) ;
112275 assert_eq ! ( "0..111....22222" , result. to_string( ) ) ;
113276
@@ -117,4 +280,20 @@ mod tests {
117280 result. to_string( )
118281 ) ;
119282 }
283+
284+ #[ test]
285+ fn block_disk_map_parse_test ( ) {
286+ let sut = BlockDiskMap :: from_str ( "12345" ) . unwrap ( ) ;
287+ let expected = BlockDiskMap {
288+ blocks : vec ! [
289+ Block :: Filled { size: 1 , id: 0 } ,
290+ Block :: Empty { size: 2 } ,
291+ Block :: Filled { size: 3 , id: 1 } ,
292+ Block :: Empty { size: 4 } ,
293+ Block :: Filled { size: 5 , id: 2 } ,
294+ ] ,
295+ } ;
296+
297+ assert_eq ! ( expected, sut) ;
298+ }
120299}
0 commit comments