From 6aac5b0c9e2301b47075fe0fcb317f507d16e504 Mon Sep 17 00:00:00 2001 From: Jonni Liljamo Date: Tue, 10 Dec 2024 20:53:59 +0200 Subject: [PATCH] feat: day9 holy unperformant my brain is not braining --- input/day9/example | 1 + src/day9/mod.rs | 11 ++++ src/day9/part1.rs | 109 +++++++++++++++++++++++++++++++ src/day9/part2.rs | 159 +++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 8 +++ 5 files changed, 288 insertions(+) create mode 100644 input/day9/example create mode 100644 src/day9/mod.rs create mode 100644 src/day9/part1.rs create mode 100644 src/day9/part2.rs diff --git a/input/day9/example b/input/day9/example new file mode 100644 index 0000000..f96c390 --- /dev/null +++ b/input/day9/example @@ -0,0 +1 @@ +2333133121414131402 diff --git a/src/day9/mod.rs b/src/day9/mod.rs new file mode 100644 index 0000000..3966e37 --- /dev/null +++ b/src/day9/mod.rs @@ -0,0 +1,11 @@ +use std::path::Path; + +mod part1; +mod part2; + +pub fn solve(input: &Path) -> anyhow::Result<()> { + println!("part one: {}", part1::part_one(input)?); + println!("part two: {}", part2::part_two(input)?); + + Ok(()) +} diff --git a/src/day9/part1.rs b/src/day9/part1.rs new file mode 100644 index 0000000..6fd08e8 --- /dev/null +++ b/src/day9/part1.rs @@ -0,0 +1,109 @@ +use std::{ + fs::File, + io::{BufRead, BufReader}, + path::Path, +}; + +#[derive(Debug)] +struct FS { + blocks: Vec, +} + +impl FS { + fn _print_blocks(&self) { + for b in &self.blocks { + match b { + FSBlock::File(id) => print!("{}", id), + FSBlock::Free => print!("."), + } + } + println!(); + } + + fn from_disk_map(disk_map: Vec) -> Self { + let mut fs = FS { blocks: vec![] }; + let mut current_id = 0; + for (i, n) in disk_map.iter().enumerate() { + if i % 2 == 0 { + for _ in 0..*n { + fs.blocks.push(FSBlock::File(current_id)); + } + current_id += 1; + } else { + for _ in 0..*n { + fs.blocks.push(FSBlock::Free); + } + } + } + fs + } + + fn compact(&mut self) { + loop { + let last_file_block = self + .blocks + .iter() + .enumerate() + .filter_map(|(i, b)| match b { + FSBlock::File(_) => Some(i), + _ => None, + }) + .last() + .unwrap(); + let first_free_block = self + .blocks + .iter() + .enumerate() + .filter_map(|(i, b)| match b { + FSBlock::Free => Some(i), + _ => None, + }) + .rev() + .last() + .unwrap(); + + if last_file_block > first_free_block { + self.blocks.swap(first_free_block, last_file_block); + //self.print_blocks(); + } else { + break; + } + } + } + + fn checksum(&self) -> usize { + self.blocks + .iter() + .enumerate() + .filter_map(|(i, b)| match b { + FSBlock::File(id) => Some(i * id), + _ => None, + }) + .collect::>() + .iter() + .sum() + } +} + +#[derive(Debug, Clone)] +enum FSBlock { + File(usize), + Free, +} + +pub fn part_one(input: &Path) -> anyhow::Result { + let mut reader = BufReader::new(File::open(input)?); + + let mut input_str = String::new(); + let _ = reader.read_line(&mut input_str)?; + let input = input_str + .trim() + .chars() + .map(|c| -> usize { c.to_string().parse().unwrap() }) + .collect(); + let mut fs = FS::from_disk_map(input); + //fs.print_blocks(); + fs.compact(); + + Ok(fs.checksum()) +} diff --git a/src/day9/part2.rs b/src/day9/part2.rs new file mode 100644 index 0000000..82083fd --- /dev/null +++ b/src/day9/part2.rs @@ -0,0 +1,159 @@ +#![allow(clippy::same_item_push)] +use std::{ + fs::File, + io::{BufRead, BufReader}, + path::Path, +}; + +#[derive(Debug, Clone)] +struct FS { + blocks: Vec, +} + +impl FS { + fn _print_blocks(&self) { + for b in &self.blocks { + match b { + FSBlock::File(id, size) => print!("{}", id.to_string().repeat(*size)), + FSBlock::Free(size) => print!("{}", ".".repeat(*size)), + } + } + println!(); + } + + fn from_disk_map(disk_map: Vec) -> Self { + let mut fs = FS { blocks: vec![] }; + let mut current_id = 0; + for (i, n) in disk_map.iter().enumerate() { + if i % 2 == 0 { + fs.blocks.push(FSBlock::File(current_id, *n)); + current_id += 1; + } else { + fs.blocks.push(FSBlock::Free(*n)); + } + } + fs + } + + fn compact(&mut self) { + let mut ignore_list = vec![]; + loop { + let self_tmp = self.clone(); + let last_file_block = match self_tmp + .blocks + .iter() + .enumerate() + .filter_map(|(i, b)| match b { + FSBlock::File(id, _) => { + if ignore_list.contains(id) { + None + } else { + Some((i, b)) + } + } + _ => None, + }) + .last() + { + Some(b) => b, + None => break, + }; + let (last_file_block_pos, FSBlock::File(last_file_block_id, last_file_block_size)) = + last_file_block + else { + unreachable!() + }; + + let first_free_block = match self_tmp + .blocks + .iter() + .enumerate() + .filter_map(|(i, b)| match b { + FSBlock::Free(size) => { + if size >= last_file_block_size { + Some((i, b)) + } else { + None + } + } + _ => None, + }) + .rev() + .last() + { + Some(b) => b, + None => { + ignore_list.push(*last_file_block_id); + continue; + } + }; + let (first_free_block_pos, FSBlock::Free(_)) = first_free_block else { + unreachable!() + }; + + ignore_list.push(*last_file_block_id); + if last_file_block_pos > first_free_block_pos { + if let Some(b) = self.blocks.get_mut(first_free_block_pos) { + match b { + FSBlock::Free(size) => *size -= last_file_block_size, + _ => unreachable!(), + } + } + + let file_block = self.blocks.remove(last_file_block_pos); + self.blocks.insert(first_free_block_pos, file_block); + self.blocks + .insert(last_file_block_pos, FSBlock::Free(*last_file_block_size)); + + //self.print_blocks(); + } + } + } + + fn checksum(&self) -> usize { + let mut a = vec![]; + for b in &self.blocks { + match b { + FSBlock::File(id, size) => { + for _ in 0..*size { + a.push(*id); + } + } + FSBlock::Free(size) => { + for _ in 0..*size { + a.push(0); + } + } + } + } + a.iter() + .enumerate() + .map(|(i, id)| i * id) + .collect::>() + .iter() + .sum() + } +} + +#[derive(Debug, Clone)] +enum FSBlock { + File(usize, usize), + Free(usize), +} + +pub fn part_two(input: &Path) -> anyhow::Result { + let mut reader = BufReader::new(File::open(input)?); + + let mut input_str = String::new(); + let _ = reader.read_line(&mut input_str)?; + let input = input_str + .trim() + .chars() + .map(|c| -> usize { c.to_string().parse().unwrap() }) + .collect(); + let mut fs = FS::from_disk_map(input); + //fs.print_blocks(); + fs.compact(); + + Ok(fs.checksum()) +} diff --git a/src/main.rs b/src/main.rs index 62cd429..f8efa78 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,6 +10,7 @@ mod day5; mod day6; mod day7; mod day8; +mod day9; #[derive(Parser)] struct Args { @@ -51,6 +52,10 @@ enum DayArgs { #[arg(short)] input: PathBuf, }, + Day9 { + #[arg(short)] + input: PathBuf, + }, } fn main() -> anyhow::Result<()> { @@ -81,6 +86,9 @@ fn main() -> anyhow::Result<()> { DayArgs::Day8 { input } => { day8::solve(&input)?; } + DayArgs::Day9 { input } => { + day9::solve(&input)?; + } } Ok(()) -- 2.44.1