diff --git a/Cargo.lock b/Cargo.lock index f87c12e..76f3d59 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -117,9 +117,6 @@ dependencies = [ [[package]] name = "day07" version = "0.1.0" -dependencies = [ - "ego-tree", -] [[package]] name = "day08" @@ -189,12 +186,6 @@ version = "0.1.0" name = "day24" version = "0.1.0" -[[package]] -name = "ego-tree" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a68a4904193147e0a8dec3314640e6db742afd5f6e634f428a6af230d9b3591" - [[package]] name = "errno" version = "0.2.8" diff --git a/day07/Cargo.toml b/day07/Cargo.toml index 0c440ae..1bbae0d 100644 --- a/day07/Cargo.toml +++ b/day07/Cargo.toml @@ -8,4 +8,3 @@ build = true app = true [dependencies] -ego-tree = "0.6.2" diff --git a/day07/src/main.rs b/day07/src/main.rs index 9b4e620..d1c95cb 100644 --- a/day07/src/main.rs +++ b/day07/src/main.rs @@ -1,13 +1,13 @@ -use ego_tree::NodeId; +#![feature(binary_heap_into_iter_sorted)] + use std::{ + cmp::Reverse, + collections::BinaryHeap, fs::File, io::{BufRead, BufReader}, + path::PathBuf, }; -type NodeMut<'t> = ego_tree::NodeMut<'t, Node>; -type NodeRef<'t> = ego_tree::NodeRef<'t, Node>; -type Tree = ego_tree::Tree; - #[derive(Debug, Default, PartialEq, Eq)] enum SolvePuzzle { First, @@ -16,147 +16,95 @@ enum SolvePuzzle { } #[derive(Debug)] -struct Node { - label: String, - size: Option, - dir: bool, +struct Collector { + pwd: PathBuf, + sums: Vec, + ext: Ext, } -struct TreeParser { - tree: Tree, - curr_node: NodeId, - reading_dir_list: bool, +trait CollectorExt: Default { + fn change_directory_up(&mut self, dir_size: usize); } -impl TreeParser { - pub fn new() -> Self { - let tree = Tree::new(Node { - label: String::from("/"), - size: None, - dir: true, - }); - Self { - curr_node: tree.root().id(), - tree, - reading_dir_list: false, - } - } +#[derive(Debug, Default)] +struct PartOne { + small_dirs_sum: usize, +} - fn read(&mut self, line: &str) { - self.reading_dir_list &= !line.starts_with("$"); +#[derive(Debug, Default)] +struct PartTwo { + smallest_relevant_dirs: BinaryHeap>, +} + +impl Collector { + pub fn push_line>(&mut self, line: S) { + let line = line.as_ref(); if line == "$ cd /" { - self.curr_node = self.tree.root().id(); + self.change_director_root() } else if line == "$ cd .." { - let node = self.curr_node(); - self.curr_node = node.parent().unwrap().id(); + self.change_directory_up() } else if line.starts_with("$ cd ") { - let node = self.curr_node(); let target = &line[5..]; - let target = node - .children() - .find(|child| child.value().label == target) - .expect("Cd target exists"); - self.curr_node = target.id(); + self.change_directory_to(target) } else if line == "$ ls" { - self.reading_dir_list = true; - } else if self.reading_dir_list == true && line.starts_with("dir ") { - let label = &line[4..]; - let mut node = self.curr_node_mut(); - node.append(Node { - label: label.to_owned(), - size: None, - dir: true, - }); - } else if self.reading_dir_list { - let (size, label) = line.split_once(' ').expect("A dir list entry"); - let mut node = self.curr_node_mut(); - node.append(Node { - label: label.to_owned(), - size: Some(size.parse().expect("Filesize is number")), - dir: false, - }); + // Just ignore + } else if line.starts_with("dir ") { + // Nothing to do } else { - panic!("What? {:?}", line); + let (size, _label) = line.split_once(' ').expect("A dir list entry"); + self.push_file(size.parse().expect("A number for dir size")) } } - fn curr_node(&self) -> NodeRef { - self.tree.get(self.curr_node).unwrap() + fn change_director_root(&mut self) { + while self.pwd.as_os_str() != "/" { + self.change_directory_up() + } } - fn curr_node_mut(&mut self) -> NodeMut { - self.tree.get_mut(self.curr_node).unwrap() + fn change_directory_up(&mut self) { + let this_dir_size = self.sums.pop().expect("At least two elements here"); + *self.sums.last_mut().expect("At least one element here") += this_dir_size; + self.pwd.pop(); + self.ext.change_directory_up(this_dir_size) } - fn finish(mut self) -> Tree { - let node_id = self.tree.root().id(); - fill_size(&mut self.tree, node_id); - self.tree + fn change_directory_to(&mut self, target: &str) { + self.pwd.push(target); + self.sums.push(0); } -} -fn fill_size(tree: &mut Tree, node_id: NodeId) { - let node_ref = tree.get(node_id); - let missing: Vec<_> = { - node_ref - .unwrap() - .children() - .filter(|child| child.value().size.is_none()) - .map(|child| child.id()) - .collect() - }; - for miss in missing { - fill_size(tree, miss); + fn push_file(&mut self, size: usize) { + *self.sums.last_mut().expect("At least one element here") += size; } - let node_ref = tree.get(node_id); - let size = node_ref - .unwrap() - .children() - .map(|child| child.value().size) - .map(Option::unwrap) - .sum(); - tree.get_mut(node_id).unwrap().value().size = Some(size); } fn solve_first_puzzle(reader: R) -> usize { - let parser = reader + reader .lines() .map(Result::unwrap) - .fold(TreeParser::new(), |mut parser, line| { - parser.read(&line); - parser - }); - let tree = parser.finish(); - tree.nodes() - .map(|node_ref| node_ref.value()) - .filter(|node| node.dir == true) - .map(|node| node.size.unwrap()) - .filter(|&size| size <= 100000) - .sum() + .collect::>() + .ext + .small_dirs_sum } fn solve_second_puzzle(reader: R) -> usize { const REQUIRED_SIZE: usize = 30_000_000; const TOTAL: usize = 70_000_000; - let parser = reader + let col = reader .lines() .map(Result::unwrap) - .fold(TreeParser::new(), |mut parser, line| { - parser.read(&line); - parser - }); - let tree = parser.finish(); - let root_size = tree.root().value().size.unwrap(); + .collect::>(); + let root_size = col.sums.first().unwrap(); let free = TOTAL - root_size; let missing = REQUIRED_SIZE.saturating_sub(free); - tree.nodes() - .map(|node_ref| node_ref.value()) - .filter(|node| node.dir == true) - .map(|node| node.size) - .map(Option::unwrap) - .filter(|&size| size >= missing) - .min() - .expect("At least one node") + col.ext + .smallest_relevant_dirs + .into_iter_sorted() + .find(|&Reverse(size)| size >= missing) + // There is at least the root dir + .unwrap() + .0 } fn main() { @@ -178,6 +126,47 @@ fn main() { println!("{}", solution); } +impl FromIterator for Collector +where + S: AsRef, + Ext: CollectorExt, +{ + fn from_iter>(iter: T) -> Self { + let mut col = iter.into_iter().fold(Self::default(), |mut acc, line| { + let line = line.as_ref(); + acc.push_line(line); + acc + }); + col.change_director_root(); + col + } +} + +impl Default for Collector { + fn default() -> Self { + Self { + ext: Ext::default(), + pwd: PathBuf::from("/"), + sums: vec![0], + } + } +} + +impl CollectorExt for PartOne { + fn change_directory_up(&mut self, dir_size: usize) { + const SMALL_DIR_MAX_SIZE: usize = 100000; + if dir_size < SMALL_DIR_MAX_SIZE { + self.small_dirs_sum += dir_size; + } + } +} + +impl CollectorExt for PartTwo { + fn change_directory_up(&mut self, dir_size: usize) { + self.smallest_relevant_dirs.push(Reverse(dir_size)) + } +} + #[cfg(test)] mod tests { use std::io::Cursor;