solution: day 9

This commit is contained in:
YK 2024-12-09 10:13:35 +03:00
parent 05e2cdebf2
commit c090ff640a
2 changed files with 170 additions and 1 deletions

View File

@ -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;

169
src/days/d9.rs Normal file
View File

@ -0,0 +1,169 @@
use crate::prelude::*;
pub type I = Vec<Block>;
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<Block> {
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<Block> {
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::<String>());
_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)
}
}