1
+ use std:: cmp:: Ordering ;
2
+ use std:: cmp:: Reverse ;
3
+ use std:: collections:: BinaryHeap ;
4
+ use std:: collections:: HashMap ;
1
5
use std:: env;
2
6
use std:: fs;
7
+ use std:: hash:: RandomState ;
3
8
4
9
fn main ( ) {
5
10
let args: Vec < String > = env:: args ( ) . collect ( ) ;
6
11
if let Ok ( disk_map) = get_disk_map ( & args[ 1 ] ) {
7
- println ! ( "{:#? }" , disk_map) ;
8
- println ! ( "{}" , solve1 ( disk_map) ) ;
12
+ println ! ( "{}" , solve_part1 ( & disk_map) ) ;
13
+ println ! ( "{}" , solve_part2 ( & disk_map) ) ;
9
14
}
10
15
}
11
16
12
- fn solve1 ( disk_map : Vec < u32 > ) -> u64 {
13
- fn file_id ( disk_map_pos : usize ) -> u32 {
14
- ( disk_map_pos as u32 ) / 2
17
+ fn solve_part2 ( disk_map : & Vec < u32 > ) -> u64 {
18
+ let block_num_and_size_list = get_block_num_and_size_list ( disk_map) ;
19
+ let mut size2free_space_heaps = create_free_space_heaps ( & block_num_and_size_list) ;
20
+ let mut checksum = 0u64 ;
21
+ for file in get_files ( & block_num_and_size_list) . iter ( ) . rev ( ) {
22
+ if let Some ( free_space) = find_free_space_for ( file, & mut size2free_space_heaps) {
23
+ checksum += calculate_checksum ( free_space. block_num , file. size , file. file_id ) ;
24
+ if free_space. size > file. size {
25
+ let new_free_space = FreeSpace {
26
+ block_num : free_space. block_num + file. size ,
27
+ size : free_space. size - file. size ,
28
+ } ;
29
+ size2free_space_heaps
30
+ . get_mut ( & new_free_space. size )
31
+ . unwrap ( )
32
+ . push ( Reverse ( new_free_space) ) ;
33
+ }
34
+ } else {
35
+ checksum += calculate_checksum ( file. block_num , file. size , file. file_id ) ;
36
+ }
37
+ }
38
+ checksum
39
+ }
40
+
41
+ fn get_block_num_and_size_list ( disk_map : & Vec < u32 > ) -> Vec < ( u32 , u32 ) > {
42
+ disk_map
43
+ . iter ( )
44
+ . scan ( 0u32 , |acc, e| {
45
+ * acc += e;
46
+ Some ( * acc - e)
47
+ } )
48
+ . zip ( disk_map. clone ( ) )
49
+ . collect :: < Vec < ( u32 , u32 ) > > ( )
50
+ }
51
+
52
+ #[ derive( Debug , Copy , Clone ) ]
53
+ struct FreeSpace {
54
+ block_num : u32 ,
55
+ size : u32 ,
56
+ }
57
+
58
+ impl Ord for FreeSpace {
59
+ fn cmp ( & self , other : & Self ) -> std:: cmp:: Ordering {
60
+ self . block_num . cmp ( & other. block_num )
61
+ }
62
+ }
63
+
64
+ impl PartialOrd for FreeSpace {
65
+ fn partial_cmp ( & self , other : & Self ) -> Option < Ordering > {
66
+ Some ( self . cmp ( other) )
67
+ }
68
+ }
69
+
70
+ impl PartialEq for FreeSpace {
71
+ fn eq ( & self , other : & Self ) -> bool {
72
+ self . block_num == other. block_num && self . size == other. size
15
73
}
16
- fn at_file ( disk_map_pos : usize ) -> bool {
17
- disk_map_pos % 2 == 0
74
+ }
75
+
76
+ impl Eq for FreeSpace { }
77
+
78
+ fn create_free_space_heaps (
79
+ block_num_and_size : & Vec < ( u32 , u32 ) > ,
80
+ ) -> HashMap < u32 , BinaryHeap < Reverse < FreeSpace > > , RandomState > {
81
+ let mut result: HashMap < u32 , BinaryHeap < Reverse < FreeSpace > > , RandomState > =
82
+ HashMap :: from_iter ( ( 1u32 ..10u32 ) . map ( |i| ( i, BinaryHeap :: new ( ) ) ) ) ;
83
+ for chunk in block_num_and_size. chunks_exact ( 2 ) {
84
+ let ( block_num, size) = chunk[ 1 ] ;
85
+ result
86
+ . get_mut ( & size)
87
+ . iter_mut ( )
88
+ . for_each ( |x| x. push ( Reverse ( FreeSpace { block_num, size } ) ) ) ;
18
89
}
90
+ result
91
+ }
92
+
93
+ #[ derive( Debug ) ]
94
+ struct File {
95
+ block_num : u32 ,
96
+ size : u32 ,
97
+ file_id : u32 ,
98
+ }
99
+
100
+ fn get_files ( block_num_and_size : & Vec < ( u32 , u32 ) > ) -> Vec < File > {
101
+ block_num_and_size
102
+ . chunks ( 2 )
103
+ . enumerate ( )
104
+ . map ( |( i, chunk) | File {
105
+ block_num : chunk[ 0 ] . 0 ,
106
+ size : chunk[ 0 ] . 1 ,
107
+ file_id : i as u32 ,
108
+ } )
109
+ . collect ( )
110
+ }
111
+
112
+ fn find_free_space_for (
113
+ file : & File ,
114
+ size2free_space_heap : & mut HashMap < u32 , BinaryHeap < Reverse < FreeSpace > > , RandomState > ,
115
+ ) -> Option < FreeSpace > {
116
+ ( file. size ..10 )
117
+ . map ( |s| size2free_space_heap[ & s] . peek ( ) )
118
+ . flatten ( )
119
+ . map ( |x| x. 0 )
120
+ . filter ( |f| f. block_num < file. block_num )
121
+ . min_by_key ( |f| f. block_num )
122
+ . map ( |free_space| {
123
+ size2free_space_heap
124
+ . get_mut ( & free_space. size )
125
+ . unwrap ( )
126
+ . pop ( ) ;
127
+ free_space
128
+ } )
129
+ }
130
+
131
+ fn solve_part1 ( disk_map : & Vec < u32 > ) -> u64 {
132
+ let at_file = |disk_map_pos : usize | disk_map_pos % 2 == 0 ;
133
+ let file_id = |disk_map_pos : usize | ( disk_map_pos as u32 ) / 2 ;
19
134
20
135
let mut front_pointer = 0 ;
21
136
let mut rear_pointer = disk_map. len ( ) - 1 ;
@@ -24,11 +139,8 @@ fn solve1(disk_map: Vec<u32>) -> u64 {
24
139
let mut checksum: u64 = 0 ;
25
140
while front_pointer < rear_pointer {
26
141
if at_file ( front_pointer) {
27
- let curr_file_id = file_id ( front_pointer) ;
28
142
let file_size = disk_map[ front_pointer] ;
29
- checksum += ( block_num..( block_num + file_size) )
30
- . map ( |b| ( b * curr_file_id) as u64 )
31
- . sum :: < u64 > ( ) ;
143
+ checksum += calculate_checksum ( block_num, file_size, file_id ( front_pointer) ) ;
32
144
block_num += file_size;
33
145
front_pointer += 1 ;
34
146
} else {
@@ -52,15 +164,18 @@ fn solve1(disk_map: Vec<u32>) -> u64 {
52
164
}
53
165
}
54
166
if front_pointer == rear_pointer {
55
- let curr_file_id = file_id ( front_pointer) ;
56
- checksum += ( block_num..( block_num + left_over_file_blocks) )
57
- . map ( |b| ( b * curr_file_id) as u64 )
58
- . sum :: < u64 > ( ) ;
167
+ checksum += calculate_checksum ( block_num, left_over_file_blocks, file_id ( front_pointer) )
59
168
}
60
169
61
170
checksum
62
171
}
63
172
173
+ fn calculate_checksum ( start_block : u32 , num_blocks : u32 , file_id : u32 ) -> u64 {
174
+ ( start_block..( start_block + num_blocks) )
175
+ . map ( |b| ( b * file_id) as u64 )
176
+ . sum :: < u64 > ( )
177
+ }
178
+
64
179
fn get_disk_map ( filename : & String ) -> std:: io:: Result < Vec < u32 > > {
65
180
let tmp1 = fs:: read_to_string ( filename) ?;
66
181
Ok ( tmp1
0 commit comments