@@ -23,137 +23,105 @@ struct Extent {
2323 length : usize ,
2424}
2525
26- fn part1 ( input : & Input ) -> usize {
27- let mut free = BTreeMap :: default ( ) ;
28- let mut files = BTreeMap :: default ( ) ;
26+ fn extents_map ( extents : & [ Extent ] ) -> BTreeMap < usize , Extent > {
27+ let mut map = BTreeMap :: new ( ) ;
28+
2929 let mut offset = 0 ;
3030
31- for ( n , len ) in input . values . iter ( ) . copied ( ) . enumerate ( ) {
32- if len == 0 {
31+ for extent in extents {
32+ if extent . length == 0 {
3333 continue ;
3434 }
3535
36- if n % 2 == 0 {
37- files. insert ( offset, Extent {
38- id : Some ( n / 2 ) ,
39- length : len,
40- } ) ;
41- } else {
42- free. insert ( offset, Extent {
43- id : None ,
44- length : len,
45- } ) ;
46- }
47- offset += len;
48- }
36+ map. insert ( offset, * extent) ;
4937
50- while let Some ( ( offset, mut hole) ) = free. pop_first ( ) {
51- let extent = if let Some ( mut entry) = files. last_entry ( ) {
52- if * entry. key ( ) < offset {
53- break ;
54- }
38+ offset += extent. length ;
39+ }
5540
56- let file = entry. get_mut ( ) ;
57- let id = file. id ;
58- let length = usize:: min ( hole. length , file. length ) ;
41+ map
42+ }
5943
60- hole . length -= length ;
61- file . length -= length ;
44+ fn checksum ( extents_map : & BTreeMap < usize , Extent > ) -> usize {
45+ let mut checksum = 0 ;
6246
63- if file. length == 0 {
64- entry. remove ( ) ;
47+ for ( & offset, extent) in extents_map {
48+ if let Some ( id) = extent. id {
49+ for n in offset..( offset + extent. length ) {
50+ checksum += n * id;
6551 }
66-
67- Extent { id, length }
68- } else {
69- panic ! ( ) ;
70- } ;
71-
72- files. insert ( offset, extent) ;
73-
74- if hole. length > 0 {
75- free. insert ( offset + extent. length , hole) ;
7652 }
7753 }
7854
55+ checksum
56+ }
7957
80- let mut checksum = 0 ;
81- for ( offset, extent) in files {
82- for n in offset..( offset + extent. length ) {
83- checksum += n * extent. id . unwrap ( ) ;
58+ fn part1 ( input : & Input ) -> usize {
59+ let mut extents_map = extents_map ( & input. values ) ;
60+
61+ loop {
62+ let ( & hole_pos, _) = extents_map. iter ( ) . find ( |( _, e) | e. id . is_none ( ) ) . unwrap ( ) ;
63+ let ( & file_pos, _) = extents_map. iter ( ) . rfind ( |( _, e) | e. id . is_some ( ) ) . unwrap ( ) ;
64+
65+ if file_pos <= hole_pos {
66+ // No more suitable holes left
67+ break ;
8468 }
85- }
8669
87- checksum
88- }
70+ let mut hole = extents_map . remove ( & hole_pos ) . unwrap ( ) ;
71+ let mut file = extents_map . remove ( & file_pos ) . unwrap ( ) ;
8972
90- fn part2 ( input : & Input ) -> usize {
91- let mut free = BTreeMap :: default ( ) ;
92- let mut files = BTreeMap :: default ( ) ;
93- let mut offset = 0 ;
73+ let size = usize:: min ( hole. length , file. length ) ;
74+ hole. length -= size;
75+ file. length -= size;
9476
95- for ( n, len) in input. values . iter ( ) . copied ( ) . enumerate ( ) {
96- if len == 0 {
97- continue ;
77+ extents_map. insert ( hole_pos, Extent { id : file. id , length : size } ) ;
78+
79+ if hole. length > 0 {
80+ extents_map. insert ( hole_pos + size, hole) ;
9881 }
9982
100- if n % 2 == 0 {
101- files. insert ( offset, Extent {
102- id : Some ( n / 2 ) ,
103- length : len,
104- } ) ;
105- } else {
106- free. insert ( offset, Extent {
107- id : None ,
108- length : len,
109- } ) ;
83+ if file. length > 0 {
84+ extents_map. insert ( file_pos, file) ;
11085 }
111- offset += len;
11286 }
11387
114- let mut defragmented = BTreeMap :: new ( ) ;
115- while let Some ( ( cur_pos, file) ) = files. pop_last ( ) {
116- let mut selected_hole = None ;
117- for ( & hole_pos, hole) in free. iter ( ) {
118- if hole_pos >= cur_pos {
119- break ;
120- }
88+ checksum ( & extents_map)
89+ }
12190
122- if file. length <= hole. length {
123- selected_hole = Some ( hole_pos) ;
124- break ;
91+ fn part2 ( input : & Input ) -> usize {
92+ let mut extents_map = extents_map ( & input. values ) ;
93+ let file_positions: Vec < _ > = extents_map. iter ( ) . filter_map ( |( & offset, extent) | {
94+ extent. id . is_some ( ) . then_some ( offset)
95+ } ) . collect ( ) ;
96+
97+ for & file_pos in file_positions. iter ( ) . rev ( ) {
98+ let len = extents_map[ & file_pos] . length ;
99+
100+ if let Some ( ( & hole_pos, _) ) = extents_map. iter ( ) . find ( |( _, e) | e. id . is_none ( ) && e. length >= len) {
101+ if hole_pos >= file_pos {
102+ // No better position found
103+ continue ;
125104 }
126- }
127105
128- if let Some ( hole_pos) = selected_hole {
129- let len = file. length ;
130- let mut hole = free. remove ( & hole_pos) . unwrap ( ) ;
106+ let file = extents_map. remove ( & file_pos) . unwrap ( ) ;
107+ let mut hole = extents_map. remove ( & hole_pos) . unwrap ( ) ;
131108
132- defragmented. insert ( hole_pos, file) ;
133- hole. length -= len;
109+ hole. length -= file. length ;
134110
135111 if hole. length > 0 {
136- free . insert ( hole_pos + len , hole) ;
112+ extents_map . insert ( hole_pos + file . length , hole) ;
137113 }
138114
139- } else {
140- defragmented. insert ( cur_pos, file) ;
141- }
142- }
143-
144- let mut checksum = 0 ;
145- for ( offset, extent) in defragmented {
146- for n in offset..( offset + extent. length ) {
147- checksum += n * extent. id . unwrap ( ) ;
115+ extents_map. insert ( hole_pos, file) ;
148116 }
149117 }
150118
151- checksum
119+ checksum ( & extents_map )
152120}
153121
154122#[ derive( Debug , Clone ) ]
155123struct Input {
156- values : Vec < usize > ,
124+ values : Vec < Extent > ,
157125}
158126
159127impl Input {
@@ -162,7 +130,16 @@ impl Input {
162130 let values = input
163131 . trim ( )
164132 . chars ( )
165- . map ( |c| c. to_digit ( 10 ) . unwrap ( ) as usize )
133+ . enumerate ( )
134+ . map ( |( n, c) | {
135+ let is_file = n % 2 == 0 ;
136+ let length = c. to_digit ( 10 ) . unwrap ( ) as usize ;
137+
138+ Extent {
139+ id : is_file. then_some ( n / 2 ) ,
140+ length,
141+ }
142+ } )
166143 . collect ( ) ;
167144
168145 Ok ( Self { values } )
0 commit comments