diff --git a/examples/2024/09.txt b/examples/2024/09.txt new file mode 100644 index 0000000..f96c390 --- /dev/null +++ b/examples/2024/09.txt @@ -0,0 +1 @@ +2333133121414131402 diff --git a/src/bin/2024/09.rs b/src/bin/2024/09.rs new file mode 100644 index 0000000..0d96eff --- /dev/null +++ b/src/bin/2024/09.rs @@ -0,0 +1,149 @@ +use advent_of_code::strings::char_to_num; +#[allow(unused_imports)] +use advent_of_code_macros::{include_data, include_example}; + +include_data!(DATA 2024 09); + +type Disk = Vec>; + +fn print_disk(disk: Disk, columns: bool) { + if columns { + for i in 1..=disk.len() { + print!("{:02}", i); + } + println!() + } + for block in disk { + match block { + None => print!(" "), + Some(x) => print!("{} ", x), + } + } + println!(";") +} + +fn layout_to_disk(layout: Vec) -> Disk { + let mut disk = Vec::new(); + let mut space = false; + let mut block; + let mut blockid = 0; + for blocksize in layout { + block = if space { + None + } else { + blockid += 1; + Some(blockid - 1) + }; + for _ in 0..blocksize { + disk.push(block); + } + space = !space; + } + disk +} + +fn calculate_checksum(disk: Disk) -> u64 { + let iter = disk.iter(); + let mut checksum = 0; + let mut position = 0; + for block in iter { + if block.is_some() { + checksum += block.unwrap() * position; + } + position += 1; + } + checksum +} + +fn compact_blocks(disk: &mut Disk) { + let mut lastblock = disk.len() - 1; + let mut block = 0; + loop { + if disk[block].is_none() { + if disk[lastblock].is_some() { + disk[block] = disk[lastblock]; + disk[lastblock] = None; + block += 1; + } + lastblock -= 1; + } else { + block += 1 + } + if lastblock <= block { + break; + } + } +} + +fn move_blocks(disk: &mut Disk, file_start: usize, length: usize, new_start: usize) { + for i in 0..=length { + disk[new_start + i] = disk[file_start - length + i]; + disk[file_start - length + i] = None; + } +} + +fn compact_files(disk: &mut Disk) { + let mut length; + let mut fileid; + let mut spaceblock; + let mut block; + let mut endblock = disk.len(); + //print_disk(disk.clone(), true); + loop { + endblock -= 1; + if endblock == 0 { + break; + } + if disk[endblock].is_some() { + fileid = disk[endblock]; + length = 0; + while disk[endblock - length] == fileid { + if endblock - length - 1 == 0 { + break; + } + length += 1; + } + if length == 0 { + break; + } + length -= 1; + block = 0; + loop { + if block + length >= disk.len() || block + length >= endblock { + endblock -= length; + break; + } + spaceblock = disk.get(block..=block + length).unwrap(); + if spaceblock.iter().all(Option::is_none) { + move_blocks(disk, endblock, length, block); + break; + } + block += 1; + } + } + //print_disk(disk.clone(), false); + } +} + +fn main() { + let mut layout = Vec::with_capacity(DATA.len()); + for char in DATA.chars() { + layout.push(char_to_num(char)); + } + let raw_disk = layout_to_disk(layout); + println!("Layout parsed"); + let mut block_disk = raw_disk.clone(); + let mut file_disk = raw_disk.clone(); + compact_blocks(&mut block_disk); + let mut cksum = calculate_checksum(block_disk); + println!( + "Checksum for the blockcompacted disk is: {}", + cksum + ); + compact_files(&mut file_disk); + cksum = calculate_checksum(file_disk); + println!( + "Checksum for the filecompacted disk is: {}", + cksum, + ); +} diff --git a/src/strings.rs b/src/strings.rs index 5c04842..9392dda 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -1,6 +1,23 @@ use num::{pow::Pow, Integer}; use std::ops::AddAssign; +#[inline] +pub fn char_to_num>(c: char) -> T { + match c { + '1' => T::from(1), + '2' => T::from(2), + '3' => T::from(3), + '4' => T::from(4), + '5' => T::from(5), + '6' => T::from(6), + '7' => T::from(7), + '8' => T::from(8), + '9' => T::from(9), + '0' => T::from(0), + _ => unreachable!(), + } +} + pub fn parsenumber + Pow + AddAssign + Copy>( input: &str, ) -> T { @@ -9,19 +26,7 @@ pub fn parsenumber + Pow + AddAssign + C let mut output: T = T::from(0); let mut mul: u32 = 0; for c in input.chars().rev() { - let i: T = match c { - '1' => T::from(1), - '2' => T::from(2), - '3' => T::from(3), - '4' => T::from(4), - '5' => T::from(5), - '6' => T::from(6), - '7' => T::from(7), - '8' => T::from(8), - '9' => T::from(9), - '0' => T::from(0), - _ => unreachable!(), - }; + let i: T = char_to_num(c); if mul > MAX_POWER { return output; } @@ -34,19 +39,7 @@ pub fn parsenumber + Pow + AddAssign + C pub fn get_numbers>(input: &str) -> Vec { let mut numbers = Vec::new(); for char in input.chars() { - match char { - '1' => numbers.push(T::from(1)), - '2' => numbers.push(T::from(2)), - '3' => numbers.push(T::from(3)), - '4' => numbers.push(T::from(4)), - '5' => numbers.push(T::from(5)), - '6' => numbers.push(T::from(6)), - '7' => numbers.push(T::from(7)), - '8' => numbers.push(T::from(8)), - '9' => numbers.push(T::from(9)), - '0' => numbers.push(T::from(0)), - _ => unimplemented!(), - } + numbers.push(char_to_num(char)); } numbers }