From ec647002cdbbfdf111040341b69db065eb390222 Mon Sep 17 00:00:00 2001 From: StNicolay Date: Mon, 9 Dec 2024 18:04:05 +0300 Subject: [PATCH] Day 9 --- src/day9.rs | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 5 +- 2 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 src/day9.rs diff --git a/src/day9.rs b/src/day9.rs new file mode 100644 index 0000000..bee63f3 --- /dev/null +++ b/src/day9.rs @@ -0,0 +1,137 @@ +use std::{ + fs::File, + io::{BufReader, Read}, + iter, +}; + +use itertools::Itertools; + +#[derive(Copy, Clone)] +enum Block { + Free, + File { id: usize }, +} + +impl Block { + fn is_free(&self) -> bool { + matches!(self, Self::Free) + } + + fn file_id(&self) -> usize { + match self { + Self::File { id } => *id, + Self::Free => unreachable!(), + } + } +} + +fn get_data() -> Vec { + let mut result = vec![]; + let reader = BufReader::new(File::open("input.txt").unwrap()); + for (i, b) in reader.bytes().enumerate() { + let num = b.unwrap() - b'0'; + let record = if i % 2 == 0 { + Block::File { id: i / 2 } + } else { + Block::Free + }; + result.extend(iter::repeat(record).take(num as usize)); + } + + result +} + +#[derive(Clone, Copy)] +struct LBlock { + start: usize, + end: usize, +} + +impl LBlock { + fn len(&self) -> usize { + self.end - self.start + } +} + +fn checksum(mem: &[Block]) -> usize { + mem.iter() + .enumerate() + .filter(|(_i, block)| !block.is_free()) + .map(|(i, block)| i * block.file_id()) + .sum() +} + +pub fn task1() { + let mut data = get_data(); + let mut lo = 0; + let mut ro = data.len() - 1; + + while lo < ro { + while lo < data.len() && !data[lo].is_free() { + lo += 1; + } + + while ro > lo && data[ro].is_free() { + ro -= 1; + } + + data.swap(lo, ro); + lo += 1; + ro = ro.saturating_sub(1); + } + + println!("{}", checksum(&data)); +} + +pub fn task2() { + let mut data = get_data(); + let mut free_mem = vec![]; + let mut files = vec![]; + for (is_free, mut chunk) in &data + .iter() + .enumerate() + .chunk_by(|(_i, block)| block.is_free()) + { + if is_free { + let (fbi, fb) = chunk.next().unwrap(); + let (last_block_index, _last_block) = chunk.last().unwrap_or((fbi, fb)); + let c_block = LBlock { + start: fbi, + end: last_block_index + 1, + }; + free_mem.push(c_block); + } else { + for (_file_id, mut chunk) in &chunk.chunk_by(|(_i, block)| block.file_id()) { + let (fbi, fb) = chunk.next().unwrap(); + let (lbi, _last_block) = chunk.last().unwrap_or((fbi, fb)); + let c_block = LBlock { + start: fbi, + end: lbi + 1, + }; + files.push(c_block); + } + }; + } + + for file in files.into_iter().rev() { + let size = file.len(); + let Some((free_index, _)) = free_mem + .iter() + .find_position(|block| block.len() >= size && block.start < file.start) + else { + continue; + }; + + let free_mem_block = &mut free_mem[free_index]; + + for (file_index, free_index) in + (file.start..file.end).zip(free_mem_block.start..free_mem_block.end) + { + data.swap(file_index, free_index); + } + + free_mem_block.start += file.len(); + } + + println!("{}", checksum(&data)); +} diff --git a/src/main.rs b/src/main.rs index 3df0c8e..7899c4d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,7 @@ mod day5; mod day6; mod day7; mod day8; +mod day9; use std::{ fs::File, @@ -23,6 +24,6 @@ fn parse_line(line: &str, pattern: char) -> impl Iterator + '_ { } fn main() { - day8::task1(); - day8::task2(); + day9::task1(); + day9::task2(); }