Skip to content

Commit adc9dec

Browse files
committed
Solve the second part of day 9 puzzle
1 parent 34ce19e commit adc9dec

File tree

2 files changed

+136
-15
lines changed

2 files changed

+136
-15
lines changed

day9/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[package]
2+
name = "day9"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]

day9/src/main.rs

Lines changed: 130 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,136 @@
1+
use std::cmp::Ordering;
2+
use std::cmp::Reverse;
3+
use std::collections::BinaryHeap;
4+
use std::collections::HashMap;
15
use std::env;
26
use std::fs;
7+
use std::hash::RandomState;
38

49
fn main() {
510
let args: Vec<String> = env::args().collect();
611
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));
914
}
1015
}
1116

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
1573
}
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 })));
1889
}
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;
19134

20135
let mut front_pointer = 0;
21136
let mut rear_pointer = disk_map.len() - 1;
@@ -24,11 +139,8 @@ fn solve1(disk_map: Vec<u32>) -> u64 {
24139
let mut checksum: u64 = 0;
25140
while front_pointer < rear_pointer {
26141
if at_file(front_pointer) {
27-
let curr_file_id = file_id(front_pointer);
28142
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));
32144
block_num += file_size;
33145
front_pointer += 1;
34146
} else {
@@ -52,15 +164,18 @@ fn solve1(disk_map: Vec<u32>) -> u64 {
52164
}
53165
}
54166
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))
59168
}
60169

61170
checksum
62171
}
63172

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+
64179
fn get_disk_map(filename: &String) -> std::io::Result<Vec<u32>> {
65180
let tmp1 = fs::read_to_string(filename)?;
66181
Ok(tmp1

0 commit comments

Comments
 (0)