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()) }