diff --git a/2024/days/09/day09/Cargo.toml b/2024/days/09/day09/Cargo.toml new file mode 100644 index 0000000..6243883 --- /dev/null +++ b/2024/days/09/day09/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "day09" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/2024/days/09/day09/src/main.rs b/2024/days/09/day09/src/main.rs new file mode 100644 index 0000000..1f6a7e2 --- /dev/null +++ b/2024/days/09/day09/src/main.rs @@ -0,0 +1,116 @@ +fn descriptor_to_disk(descriptor: String) -> Vec { + let mut file_index: i64 = 0; + let mut disk: Vec = Vec::new(); + for (i, item) in descriptor.chars().enumerate() { + let item = item.to_digit(10); + if let Some(item) = item { + // If we are on a file + if i % 2 == 0 { + for _ in 0..item { + disk.push(file_index); + } + file_index += 1; + } else { + for _ in 0..item { + disk.push(-1); + } + } + } + } + disk +} + +fn fragment(disk: &Vec) -> Vec { + let mut disk = disk.clone(); + let mut i: usize = 0; + let mut j: usize = disk.len() - 1; + while i < j { + // If there is an empty slot + if disk[i] == -1 { + if disk[j] == -1 { + j -= 1; + } else { + // Swap an empty slot with an occupied slot + let tmp = disk[i]; + disk[i] = disk[j]; + disk[j] = tmp; + } + } else { + i += 1; + } + } + disk +} + + +fn move_file(disk: &mut Vec, file_index: i64, file_length: usize, previous_start: usize, next_start: usize) { + for i in 0..file_length { + disk[previous_start + i] = -1; + } + for i in 0..file_length { + disk[next_start + i] = file_index; + } +} + +fn contiguous_empty(disk: &Vec, start_index: usize, file_length: usize) -> bool { + for i in start_index..(start_index + file_length) { + if i > disk.len() || disk[i] != -1 { + return false; + } + } + return true; +} + +fn find_position(disk: &Vec, start_index: usize, file_length: usize) -> Option { + for i in 0..start_index { + if disk[i] == -1 && contiguous_empty(disk, i, file_length) { + return Some(i); + } + } + None +} + +fn defragment(disk: &Vec) -> Vec { + let mut disk = disk.clone(); + let max_file_index = disk.iter().cloned().fold(0, i64::max); + let mut file_index = max_file_index; + while file_index >= 0 { + let mut start_index: usize = 0; + while disk[start_index] != file_index { + start_index += 1; + } + let mut file_length: usize = 0; + while start_index + file_length < disk.len() && disk[start_index + file_length] == file_index { + file_length += 1; + } + if let Some(next_index) = find_position(&disk, start_index, file_length) { + move_file(&mut disk, file_index, file_length, start_index, next_index); + } + file_index -= 1; + } + disk +} + +fn checksum(disk: &Vec) -> i64 { + let mut sum = 0; + for (i, item) in disk.iter().enumerate() { + if *item != -1 { + sum += i as i64 * (*item); + } + } + sum +} + +fn main() -> std::io::Result<()> { + let disk_descriptor: String = std::io::read_to_string(std::io::stdin())?; + let disk = descriptor_to_disk(disk_descriptor); + // Part 1. + let disk1 = fragment(&disk); + let check1 = checksum(&disk1); + println!("{}", check1); + // Part 2 + let disk2 = defragment(&disk); + let check2 = checksum(&disk2); + println!("{}", check2); + Ok(()) +}