diff --git a/src/days.rs b/src/days.rs index 0d27540..18c513c 100644 --- a/src/days.rs +++ b/src/days.rs @@ -6,7 +6,7 @@ pub mod d5; pub mod d6; pub mod d7; pub mod d8; -// pub mod d9; +pub mod d9; // pub mod d10; // pub mod d11; // pub mod d12; diff --git a/src/days/d9.rs b/src/days/d9.rs new file mode 100644 index 0000000..2dcb817 --- /dev/null +++ b/src/days/d9.rs @@ -0,0 +1,169 @@ +use crate::prelude::*; + +pub type I = Vec; +pub type O = usize; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Block { + Empty { size: usize }, + Taken { id: usize, size: usize } +} + +fn _parse_silver (i: SS) -> Vec { + let mut switch = true; + let mut out = Vec::with_capacity(i.len() * 10); + let mut id = 0; + for c in i.chars() { + let val = (c as u8 - b'0') as usize; + if switch { + out.push(Block::Taken { id, size: val }); + id += 1; + } else { + out.extend((0..val).map(|_| Block::Empty { size: 1 })); + } + switch = !switch; + } + + out +} + +fn _parse_gold (i: SS) -> Vec { + let mut switch = true; + let mut out = Vec::with_capacity(i.len() * 10); + let mut id = 0; + for c in i.chars() { + let val = (c as u8 - b'0') as usize; + if switch { + out.push(Block::Taken { id, size: val }); + id += 1; + } else { + out.push(Block::Empty { size: val }); + } + switch = !switch; + } + + out +} + +fn _checksum (data: &I) -> usize { + let mut position = 0; + let mut sum = 0; + + for d in data { + match d { + Block::Taken { id, size } => { + for _ in 0..*size { + sum += position * id; + position += 1; + } + }, + Block::Empty { size } => position += size + } + } + + sum +} + +fn _silver (mut data: I) -> O { + let mut left = 0; + let mut right = data.len() - 1; + + while left < right { + while di!(data[right], Block::Empty { size: 0 }) { + right -= 1; + } + + let Block::Taken { id, mut size } = data[right] else { break; }; + data[right] = Block::Empty { size: 0 }; + + while size > 0 { + while di!(data[left], Block::Taken { id: 0, size: 0 }) { + left += 1; + } + + data[left] = Block::Taken { id, size: 1 }; + size -= 1; + } + } + + _checksum(&data) +} + +fn _gold (mut data: I) -> O { + let mut left = 0; + let mut right = data.len() - 1; + + 'outer : while left < right { + while di!(data[right], Block::Empty { size: 0 }) { + right -= 1; + } + + 'mid : loop { + if left >= right { + right -= 1; + left = 0; + continue 'outer; + } + + while let Block::Taken { .. } = data[left] { + left += 1; + continue 'mid; + } + + let Block::Taken { id, size } = data[right] else { break; }; + + if let Block::Empty { size: size_block } = data[left] && size_block >= size { + data[left] = Block::Taken { id, size }; + data[right] = Block::Empty { size }; + + if size_block > size { + let rest = size_block - size; + data.insert(left + 1, Block::Empty { size: rest }); + right += 1; + } + + left = 0; + + } else { + left += 1; + } + } + + } + // 425499176500 low + // println!("{:?}", data.iter().map(|e| match e { + // Block::Empty { size } => format!("{}", ".".repeat(*size)), + // Block::Taken { id, size } => format!("{}", id.to_string().repeat(*size)) + // }).collect::()); + _checksum(&data) +} + +#[cfg(test)] +mod test { + use super::*; + + fn read () -> SS { + inc!(9) + } + + #[test] + fn sample () { + let data = "2333133121414131402"; + assert_eq!(_silver(_parse_silver(data)), 1928); + assert_eq!(_gold(_parse_gold(data)), 2858); + } + + #[test] + fn silver () { + let ans = _silver(_parse_silver(read())); + + assert_eq!(ans, 6310675819476) + } + + #[test] + fn gold () { + let ans = _gold(_parse_gold(read())); + + assert_eq!(ans, 1) + } +}