Day 9: Disk Fragmenter
Megathread guidelines
- Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
- You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL
FAQ
- What is this?: Here is a post with a large amount of details: https://programming.dev/post/6637268
- Where do I participate?: https://adventofcode.com/
- Is there a leaderboard for the community?: We have a programming.dev leaderboard with the info on how to join in this post: https://programming.dev/post/6631465
Rust
A bunch of fiddling with indices and sizes. In part 1 the disk is simulated in a Vec, for part 2 files and spaces are represented by their offset and size, collected in separate lists. Then these values are changed as necessary, with a whole bunch of
mut
. In particular, files are never moved within the list of files, only their offset changes.Solution
fn part1(input: String) { let mut id: u64 = 0; let mut disk = Vec::new(); let mut file = true; for b in input.trim().bytes() { let num: usize = (b - b'0') as usize; if file { disk.extend(vec![Some(id); num]); id += 1; } else { disk.extend(vec![None; num]); } file = !file; } let mut first_free = 0; while disk[first_free].is_some() { first_free += 1 } let mut last_file = disk.len() - 1; while disk[last_file].is_none() { last_file -= 1 } while first_free < last_file { disk[first_free] = disk[last_file]; disk[last_file] = None; while disk[first_free].is_some() { first_free += 1 } while disk[last_file].is_none() { last_file -= 1 } } let checksum = disk .iter() .filter_map(|e| *e) .enumerate() .map(|(i, id)| i as u64 * id) .sum::<u64>(); println!("{checksum}"); } fn part2(input: String) { // Tuples of (idx, size) let mut free_spaces = Vec::new(); // Tuples of (idx, size, id) let mut files = Vec::new(); let mut id: u64 = 0; let mut disk_len = 0; let mut file = true; for b in input.trim().bytes() { let num = (b - b'0') as u64; if file { files.push((disk_len, num, id)); id += 1; } else { free_spaces.push((disk_len, num)); } disk_len += num; file = !file; } for (idx, size, _id) in files.iter_mut().rev() { match free_spaces .iter_mut() // Only search spaces left of file .take_while(|(sp_idx, _space)| sp_idx < idx) .find(|(_sp_idx, space)| space >= size) { None => {} // No space found Some((sp_idx, space)) => { // Move file into space *idx = *sp_idx; // Reduce free space *sp_idx += *size; *space -= *size; } } } let sum_range = |n| if n == 0 { 0 } else { (n * (n - 1)) / 2 }; let checksum = files .iter() .map(|(idx, size, id)| (sum_range(idx + size) - sum_range(*idx)) * id) .sum::<u64>(); println!("{checksum}"); } util::aoc_main!();
Also on github