@@ -4,6 +4,7 @@ advent_of_code::solution!(9);
4
4
5
5
#[ derive( Debug , Clone ) ]
6
6
struct Block {
7
+ start_idx : usize ,
7
8
length : u32 ,
8
9
file_id : Option < u32 > ,
9
10
}
@@ -19,10 +20,12 @@ impl Block {
19
20
} else {
20
21
(
21
22
Block {
22
- length : length,
23
+ start_idx : self . start_idx ,
24
+ length,
23
25
file_id : self . file_id ,
24
26
} ,
25
27
Some ( Block {
28
+ start_idx : self . start_idx + length as usize ,
26
29
length : self . length - length,
27
30
file_id : self . file_id ,
28
31
} ) ,
@@ -31,36 +34,6 @@ impl Block {
31
34
}
32
35
}
33
36
34
- // struct BlocksFmt<'a>(&'a Vec<Block>);
35
-
36
- // impl Debug for BlocksFmt<'_> {
37
- // fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38
- // for block in self.0 {
39
- // for _ in 0..block.length {
40
- // match block.file_id {
41
- // Some(id) => write!(f, "{}", id)?,
42
- // None => write!(f, ".")?,
43
- // }
44
- // }
45
- // }
46
- // Ok(())
47
- // }
48
- // }
49
-
50
- fn checksum ( blocks : & Vec < Block > ) -> u64 {
51
- let mut sum: u64 = 0 ;
52
- let mut idx = 0 ;
53
- for block in blocks {
54
- for _ in 0 ..block. length {
55
- if let Some ( file_id) = block. file_id {
56
- sum += idx * ( file_id as u64 ) ;
57
- }
58
- idx += 1 ;
59
- }
60
- }
61
- sum
62
- }
63
-
64
37
fn parse_blocks ( input : & str ) -> Vec < Block > {
65
38
let nums = input
66
39
. chars ( )
@@ -69,6 +42,7 @@ fn parse_blocks(input: &str) -> Vec<Block> {
69
42
. map ( |r| r. unwrap ( ) ) ;
70
43
71
44
let mut blocks = Vec :: with_capacity ( 1000 ) ;
45
+ let mut idx = 0 ;
72
46
for ( i, num) in nums. enumerate ( ) {
73
47
let file_id = if i % 2 == 0 {
74
48
Some ( ( i / 2 ) as u32 )
@@ -81,11 +55,13 @@ fn parse_blocks(input: &str) -> Vec<Block> {
81
55
}
82
56
83
57
let b = Block {
58
+ start_idx : idx,
84
59
file_id,
85
60
length : num,
86
61
} ;
87
62
88
63
blocks. push ( b) ;
64
+ idx += num as usize ;
89
65
}
90
66
91
67
blocks
@@ -149,11 +125,15 @@ pub fn part_two(input: &str) -> Option<u64> {
149
125
spaces_block_indices_by_size[ b. length as usize ] . push ( i) ;
150
126
} ) ;
151
127
152
- let mut right_block_idx = blocks. len ( ) - 1 ;
153
- while right_block_idx > 0 {
128
+ let mut checksum = 0 ;
129
+
130
+ for right_block_idx in ( 0 ..blocks. len ( ) ) . rev ( ) {
154
131
let right_block = & blocks[ right_block_idx] . clone ( ) ;
155
132
if right_block. is_free ( ) {
156
- right_block_idx -= 1 ;
133
+ continue ;
134
+ }
135
+
136
+ if right_block. length == 0 {
157
137
continue ;
158
138
}
159
139
@@ -167,50 +147,47 @@ pub fn part_two(input: &str) -> Option<u64> {
167
147
}
168
148
}
169
149
150
+ // can't move the file, so just add to the checksum
170
151
if best_free_space_block_idx == usize:: MAX {
171
- right_block_idx -= 1 ;
152
+ checksum += ( 0 ..right_block. length as u64 )
153
+ . map ( |i| ( right_block. start_idx as u64 + i) )
154
+ . sum :: < u64 > ( )
155
+ * right_block. file_id . unwrap ( ) as u64 ;
172
156
continue ;
173
157
}
174
158
175
159
let left_block_idx = best_free_space_block_idx;
176
- let left_block = & blocks[ left_block_idx] ;
160
+ let left_block = & blocks[ left_block_idx] . clone ( ) ;
177
161
spaces_block_indices_by_size[ left_block. length as usize ] . pop ( ) ;
178
162
179
163
let ( _, maybe_left_additional_space) = left_block. split ( right_block. length ) ;
180
164
if let Some ( left_additional_space) = maybe_left_additional_space {
181
- let new_idx = left_block_idx + 1 ;
182
- blocks. insert ( left_block_idx, right_block. clone ( ) ) ;
183
-
184
- // shift all the indices that are greater than the left block index
185
- spaces_block_indices_by_size
186
- . iter_mut ( )
187
- . flat_map ( |space_list| space_list. iter_mut ( ) )
188
- . filter ( |idx| * * idx > left_block_idx)
189
- . for_each ( |idx| * idx += 1 ) ;
190
-
191
165
// add the new space to the list
192
166
let space_list =
193
167
& mut spaces_block_indices_by_size[ left_additional_space. length as usize ] ;
194
168
let mut insert_idx = space_list. len ( ) ;
195
169
for i in ( 0 ..space_list. len ( ) ) . rev ( ) {
196
- if space_list[ i] > new_idx {
170
+ if space_list[ i] > left_block_idx {
197
171
break ;
198
172
}
199
173
insert_idx = i;
200
174
}
201
- space_list. insert ( insert_idx, new_idx ) ;
175
+ space_list. insert ( insert_idx, left_block_idx ) ;
202
176
203
- blocks[ new_idx] = left_additional_space;
204
- right_block_idx += 1 ;
177
+ blocks[ left_block_idx] = left_additional_space;
205
178
} else {
206
- blocks[ left_block_idx] = right_block . clone ( ) ;
179
+ blocks[ left_block_idx] . length = 0 ;
207
180
}
208
181
209
- blocks[ right_block_idx] . file_id = None ;
210
- right_block_idx -= 1 ;
182
+ let checksum_contribution = ( 0 ..right_block. length as u64 )
183
+ . map ( |i| ( left_block. start_idx as u64 + i) )
184
+ . sum :: < u64 > ( )
185
+ * right_block. file_id . unwrap ( ) as u64 ;
186
+
187
+ checksum += checksum_contribution
211
188
}
212
189
213
- Some ( checksum ( & blocks ) )
190
+ Some ( checksum)
214
191
}
215
192
216
193
#[ cfg( test) ]
0 commit comments