diff --git a/dump.txt b/dump.txt new file mode 100644 index 0000000..72ee2db --- /dev/null +++ b/dump.txt @@ -0,0 +1,42 @@ +id = 0, size = 2, ptr = 0 +id = 0, size = 2, ptr = 0 +id = 9, size = 2, ptr = 40 +id = 9, size = 2, ptr = 40 +id = 2, size = 1, ptr = 11 +id = 1, size = 3, ptr = 5 +id = 1, size = 3, ptr = 5 +id = 1, size = 3, ptr = 5 +id = 7, size = 3, ptr = 32 +id = 7, size = 3, ptr = 32 +id = 7, size = 3, ptr = 32 +. +id = 4, size = 2, ptr = 19 +id = 4, size = 2, ptr = 19 +. +id = 3, size = 3, ptr = 15 +id = 3, size = 3, ptr = 15 +id = 3, size = 3, ptr = 15 +. +. +. +. +id = 5, size = 4, ptr = 22 +id = 5, size = 4, ptr = 22 +id = 5, size = 4, ptr = 22 +id = 5, size = 4, ptr = 22 +. +id = 6, size = 4, ptr = 27 +id = 6, size = 4, ptr = 27 +id = 6, size = 4, ptr = 27 +id = 6, size = 4, ptr = 27 +. +. +. +. +. +id = 8, size = 4, ptr = 36 +id = 8, size = 4, ptr = 36 +id = 8, size = 4, ptr = 36 +id = 8, size = 4, ptr = 36 +. +. diff --git a/predump.txt b/predump.txt new file mode 100644 index 0000000..a15f55c --- /dev/null +++ b/predump.txt @@ -0,0 +1,42 @@ +id = 0, size = 2, ptr = 0 +id = 0, size = 2, ptr = 0 +. +. +. +id = 1, size = 3, ptr = 5 +id = 1, size = 3, ptr = 5 +id = 1, size = 3, ptr = 5 +. +. +. +id = 2, size = 1, ptr = 11 +. +. +. +id = 3, size = 3, ptr = 15 +id = 3, size = 3, ptr = 15 +id = 3, size = 3, ptr = 15 +. +id = 4, size = 2, ptr = 19 +id = 4, size = 2, ptr = 19 +. +id = 5, size = 4, ptr = 22 +id = 5, size = 4, ptr = 22 +id = 5, size = 4, ptr = 22 +id = 5, size = 4, ptr = 22 +. +id = 6, size = 4, ptr = 27 +id = 6, size = 4, ptr = 27 +id = 6, size = 4, ptr = 27 +id = 6, size = 4, ptr = 27 +. +id = 7, size = 3, ptr = 32 +id = 7, size = 3, ptr = 32 +id = 7, size = 3, ptr = 32 +. +id = 8, size = 4, ptr = 36 +id = 8, size = 4, ptr = 36 +id = 8, size = 4, ptr = 36 +id = 8, size = 4, ptr = 36 +id = 9, size = 2, ptr = 40 +id = 9, size = 2, ptr = 40 diff --git a/src/main.rs b/src/main.rs index e78e69f..f7e52eb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -30,6 +30,7 @@ fn main() -> Result<()> { 6 => AocDaySixSolution, 7 => AocDaySevenSolution, 8 => AocDayEightSolution, + 9 => AocDayNineSolution }; Ok(()) diff --git a/src/solutions/day_7.rs b/src/solutions/day_7.rs index 8a79b56..33f5f09 100644 --- a/src/solutions/day_7.rs +++ b/src/solutions/day_7.rs @@ -154,24 +154,3 @@ impl AocSolution for AocDaySevenSolution { Ok(sum) } } - -#[test] -fn test() { - let sol = AocDaySevenSolution; - - assert_eq!( - sol.part_one( - r#"190: 10 19 -3267: 81 40 27 -83: 17 5 -156: 15 6 -7290: 6 8 6 15 -161011: 16 10 13 -192: 17 8 14 -21037: 9 7 18 13 -292: 11 6 16 20"# - ) - .unwrap(), - 3749 - ); -} diff --git a/src/solutions/day_9.rs b/src/solutions/day_9.rs index 7980846..19d6033 100644 --- a/src/solutions/day_9.rs +++ b/src/solutions/day_9.rs @@ -1,8 +1,150 @@ -use std::{fs::read_to_string, path::Path}; +use std::{collections::HashMap, fs::read_to_string, iter::from_fn, path::Path}; use super::AocSolution; use crate::utils::Result; +fn checksum(fs: &[Option]) -> u64 { + fs.iter() + .copied() + .zip(0..) + .filter_map(|(n, m)| n.map(|n| n * m)) + .sum() +} + +#[derive(Debug, Clone, Copy)] +struct Filedata { + size: usize, + ptr: usize, +} + +impl Filedata { + const fn new(size: usize, ptr: usize) -> Self { + Self { size, ptr } + } +} + +#[derive(Debug)] +struct Disk { + pub id: u64, + pub metadata: HashMap, + pub fs: Vec>, +} + +impl Disk { + fn new(src: &str) -> Self { + let total = src.len(); + let mut flag = false; + + let (fs, metadata, id) = src + .chars() + .zip(from_fn(move || { + flag = !flag; + Some(flag) + })) + .filter_map(|(ch, flag)| match ch { + '0' => Some((0, flag)), + '1' => Some((1, flag)), + '2' => Some((2, flag)), + '3' => Some((3, flag)), + '4' => Some((4, flag)), + '5' => Some((5, flag)), + '6' => Some((6, flag)), + '7' => Some((7, flag)), + '8' => Some((8, flag)), + '9' => Some((9, flag)), + _ => None, + }) + .fold( + (Vec::with_capacity(total), HashMap::new(), 0), + |(mut v, mut meta, mut id), (len, flag)| { + let idx = v.len(); + for _ in 0..len { + if flag { + meta.insert(id, Filedata::new(len, idx)); + } + + v.push(if flag { Some(id) } else { None }); + } + + if flag { + id += 1 + } + + (v, meta, id) + }, + ); + + Self { id, fs, metadata } + } + + fn sort(&mut self) -> u64 { + let (mut first, mut last) = (0, self.fs.len() - 1); + + fn _is_continous(fs: &[Option]) -> bool { + if let Some(first_none) = fs.iter().position(|o| o.is_none()) { + fs[first_none..].iter().all(|o| o.is_none()) + } else { + true + } + } + + while !_is_continous(&self.fs) { + while self.fs[first].is_some() { + first += 1; + } + + while self.fs[last].is_none() { + last -= 1; + } + + self.fs.swap(first, last); + } + + checksum(&self.fs) + } + + fn sort_block(&mut self) -> u64 { + fn swap_block(fs: &mut [Option], a: usize, b: usize, size: usize) { + for offset in 0..size { + if fs[a + offset].is_none() || fs[b + offset].is_some() { + fs.swap(a + offset, b + offset); + } + } + } + + fn allocate(fs: &[Option], size: usize, limit: usize) -> Option { + let mut offset = 0; + + loop { + let slice = match fs.get(offset..(offset + size)) { + Some(sl) => sl, + None => return None, + }; + + if slice.iter().all(|o| o.is_none()) { + break; + } + + offset += 1; + if offset >= limit { + return None; + } + } + + Some(offset) + } + + for id in (0..self.id).rev() { + let metadata = &self.metadata[&id]; + if let Some(ptr) = allocate(&self.fs, metadata.size, metadata.ptr) { + swap_block(&mut self.fs, ptr, metadata.ptr, metadata.size); + } + } + + checksum(&self.fs) + } +} + pub struct AocDayNineSolution; impl AocSolution for AocDayNineSolution { @@ -11,15 +153,17 @@ impl AocSolution for AocDayNineSolution { fn get_input(&self, path: Option<&Path>) -> Result { Ok(match path { Some(p) => read_to_string(p)?, - None => read_to_string("./input/day_day_9.txt")?, + None => read_to_string("./input/day_9.txt")?, }) } fn part_one(&self, input: &str) -> Result { - todo!() + let mut disk = Disk::new(input); + Ok(disk.sort()) } fn part_two(&self, input: &str) -> Result { - todo!() + let mut disk = Disk::new(input); + Ok(disk.sort_block()) } } diff --git a/src/utils/macros.rs b/src/utils/macros.rs index 94f746f..54204c1 100644 --- a/src/utils/macros.rs +++ b/src/utils/macros.rs @@ -1,6 +1,6 @@ #[macro_export] macro_rules! map_solution { - ($cli:ident : $($day:expr => $sol:expr,)+ $(,)?) => { + ($cli:ident : $($day:expr => $sol:expr),+ $(,)?) => { match $cli .day { $($day => { let sol = $sol; diff --git a/src/utils/mod.rs b/src/utils/mod.rs index f7453b7..8953cab 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -21,4 +21,13 @@ pub enum Error { InvalidInput, #[error("Unsupported day.")] UnsupportedDay, + #[error("{0}")] + CustomError(String), +} + +#[macro_export] +macro_rules! err { + ($lit:literal) => { + $crate::utils::Error::CustomError($lit.to_string()) + }; }