From da74a98b8b9ebd8641f600d69dcf422e825eddce Mon Sep 17 00:00:00 2001 From: Joe Ardent <code@ardent.nebcorp.com> Date: Sun, 5 Jan 2025 14:49:47 -0800 Subject: [PATCH] day9, part2 --- day09/src/main.rs | 209 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 200 insertions(+), 9 deletions(-) diff --git a/day09/src/main.rs b/day09/src/main.rs index b898ef3..b97ad4a 100644 --- a/day09/src/main.rs +++ b/day09/src/main.rs @@ -1,6 +1,12 @@ +use std::{ + collections::HashSet, + fmt::{Debug, Display, Write}, +}; + fn main() { let input = std::fs::read_to_string("input").unwrap(); println!("{}", pt1(&input)); + println!("{}", pt2(&input)); } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -10,7 +16,6 @@ enum Cell { } fn pt1(input: &str) -> usize { - let mut next_id = 0; let mut map = Vec::new(); let mut frees = Vec::new(); for (i, c) in input.chars().enumerate() { @@ -21,11 +26,10 @@ fn pt1(input: &str) -> usize { } }; if i % 2 == 0 { - let cell = Cell::Block(next_id); + let cell = Cell::Block(i / 2); for _ in 0..n { map.push(cell); } - next_id += 1; } else { for _ in 0..n { frees.push(map.len()); @@ -47,6 +51,100 @@ fn pt1(input: &str) -> usize { map.swap(free, i); } + map.iter() + .enumerate() + .map(|(i, &b)| match b { + Cell::Block(v) => i * v, + _ => 0, + }) + .sum() +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +enum Block { + Free(FreeBlock), + // size, id + File(FileBlock), +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +struct FreeBlock { + size: usize, +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +struct FileBlock { + size: usize, + id: usize, +} + +impl Block { + fn is_free(&self) -> Option<usize> { + match self { + Block::Free(s) => Some(s.size), + _ => None, + } + } + + fn size(&self) -> usize { + match self { + Block::Free(block) => block.size, + Block::File(block) => block.size, + } + } + + fn set_size(&mut self, s: usize) { + match self { + Block::Free(block) => block.size = s, + Block::File(block) => block.size = s, + } + } +} + +fn pt2(input: &str) -> usize { + let mut map = Vec::new(); + + for (i, c) in input.chars().enumerate() { + let n = match c.to_digit(10) { + Some(n) => n as usize, + _ => { + continue; + } + }; + if i % 2 == 0 { + let cell = Block::File(FileBlock { size: n, id: i / 2 }); + map.push(cell); + } else { + map.push(Block::Free(FreeBlock { size: n })); + } + } + + let mut processed = HashSet::new(); + let mut done = false; + while !done { + for i in (0..map.len()).rev() { + if i == 0 { + done = true; + } + match map[i] { + Block::Free(_) => { + continue; + } + Block::File(file) => { + if processed.contains(&file.id) { + continue; + } + processed.insert(file.id); + if move_file(&mut map, i) { + map = compact(&map); + break; + } + } + } + } + } + let map = render_map(&map); + //println!("{map:?}"); map.iter() @@ -58,14 +156,102 @@ fn pt1(input: &str) -> usize { .sum() } -enum Block { - Free(usize), - // size, id - Block(usize, usize), +fn move_file(map: &mut Vec<Block>, file_index: usize) -> bool { + let file_size = map[file_index].size(); + for j in 0..file_index { + if let Some(free_size) = map[j].is_free() { + if map[file_index].size() <= free_size { + map.swap(file_index, j); + let diff = free_size - file_size; + if diff > 0 { + map[file_index].set_size(file_size); + map.insert(j + 1, Block::Free(FreeBlock { size: diff })); + return true; + } + break; + } + } + } + false } -fn pt2(input: &str) -> usize { - todo!() +fn render_map(map: &[Block]) -> Vec<Cell> { + let mut out = Vec::new(); + + for block in map { + match block { + Block::Free(free) => { + for _ in 0..free.size { + out.push(Cell::Free); + } + } + Block::File(file) => { + for _ in 0..file.size { + out.push(Cell::Block(file.id)); + } + } + } + } + + out +} + +impl Display for Block { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Block::Free(FreeBlock { size: s }) => { + let out = (0..*s).fold(String::new(), |mut out, _| { + let _ = write!(out, "."); + out + }); + write!(f, "{out}") + } + Block::File(FileBlock { size: sz, id }) => { + let out = (0..*sz).fold(String::new(), |mut out, _| { + if out.is_empty() { + let _ = write!(out, "{id}"); + } else { + let _ = write!(out, "|{id}"); + } + out + }); + write!(f, "{out}") + } + } + } +} + +impl Debug for Block { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Block::Free(s) => write!(f, "free: {}", s.size), + Block::File(b) => write!(f, "{}: {}", b.id, b.size), + } + } +} + +fn compact(v: &[Block]) -> Vec<Block> { + let mut out = Vec::new(); + let mut i = 0; + + while i < v.len() { + match v[i] { + Block::File(file) => out.push(Block::File(file)), + Block::Free(free) => { + let mut total = free.size; + while let Some(next_free_size) = v.get(i + 1).and_then(|b| b.is_free()) { + total += next_free_size; + i += 1; + } + if total > 0 { + out.push(Block::Free(FreeBlock { size: total })); + } + } + } + i += 1; + } + + out } #[cfg(test)] @@ -79,4 +265,9 @@ mod test { let v = pt1(INPUT); assert_eq!(v, 1928); } + #[test] + fn p2() { + let v = pt2(INPUT); + assert_eq!(v, 2858); + } }