From 93d7537f6689f63482158ec20332e4f66ab7b16b Mon Sep 17 00:00:00 2001 From: vodofrede Date: Tue, 30 May 2023 15:04:49 +0200 Subject: [PATCH] 2022-7... --- src/bin/2022-7.rs | 169 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 src/bin/2022-7.rs diff --git a/src/bin/2022-7.rs b/src/bin/2022-7.rs new file mode 100644 index 0000000..7de4004 --- /dev/null +++ b/src/bin/2022-7.rs @@ -0,0 +1,169 @@ +use eyes::parse; +use itertools::Itertools; +use std::{cell::RefCell, collections::HashMap, iter, rc::Rc}; + +fn main() { + let input = aoc::input!(); + println!("part 1: {}", part1(&input)); + println!("part 1: {}", part2(&input)); +} + +type RefNode = Rc>; +#[derive(Default)] +struct Node { + size: u64, + children: HashMap, + parent: Option, +} + +impl Node { + fn total_size(&self) -> u64 { + self.children + .values() + .map(|child| child.borrow().total_size()) + .sum::() + + self.size + } +} + +fn all_dirs(n: RefNode) -> Box> { + let children = n.borrow().children.values().cloned().collect::>(); + + Box::new( + iter::once(n).chain( + children + .into_iter() + .filter_map(|c| { + if c.borrow().size == 0 { + Some(all_dirs(c)) + } else { + None + } + }) + .flatten(), + ), + ) +} + +fn part1(input: &str) -> u64 { + let root = RefNode::default(); + let mut node = root.clone(); + + for line in input.lines() { + match line { + l if l.starts_with("$ cd") => { + let dir = parse!(l, "$ cd {}", String); + match dir.as_str() { + "/" => continue, + ".." => { + let parent = node.borrow().parent.clone().unwrap(); + node = parent; + } + _ => { + let child = node.borrow_mut().children.entry(dir).or_default().clone(); + node = child; + } + } + } // cd + l if l.starts_with("$ ls") => continue, // ls + l if l.starts_with("dir ") => { + // dir entry + let dir = parse!(l, "dir {}", String); + let entry = node.borrow_mut().children.entry(dir).or_default().clone(); + entry.borrow_mut().parent = Some(node.clone()); + } + l => { + // file entry + let (size, file) = parse!(l, "{} {}", u64, String); + let entry = node.borrow_mut().children.entry(file).or_default().clone(); + entry.borrow_mut().size = size; + entry.borrow_mut().parent = Some(node.clone()); + } + } + } + + all_dirs(root) + .map(|d| d.borrow().total_size()) + .filter(|&s| s <= 100_000) + .sum::() +} + +fn part2(input: &str) -> u64 { + let root = RefNode::default(); + let mut node = root.clone(); + + for line in input.lines() { + match line { + l if l.starts_with("$ cd") => { + let dir = parse!(l, "$ cd {}", String); + match dir.as_str() { + "/" => continue, + ".." => { + let parent = node.borrow().parent.clone().unwrap(); + node = parent; + } + _ => { + let child = node.borrow_mut().children.entry(dir).or_default().clone(); + node = child; + } + } + } // cd + l if l.starts_with("$ ls") => continue, // ls + l if l.starts_with("dir ") => { + // dir entry + let dir = parse!(l, "dir {}", String); + let entry = node.borrow_mut().children.entry(dir).or_default().clone(); + entry.borrow_mut().parent = Some(node.clone()); + } + l => { + // file entry + let (size, file) = parse!(l, "{} {}", u64, String); + let entry = node.borrow_mut().children.entry(file).or_default().clone(); + entry.borrow_mut().size = size; + entry.borrow_mut().parent = Some(node.clone()); + } + } + } + + let free_space = 70000000 - root.borrow().total_size(); + all_dirs(root) + .map(|d| d.borrow().total_size()) + .filter(|&s| s >= 30000000 - free_space) + .min() + .unwrap() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn examples() { + let example = r#"$ cd / +$ ls +dir a +14848514 b.txt +8504156 c.dat +dir d +$ cd a +$ ls +dir e +29116 f +2557 g +62596 h.lst +$ cd e +$ ls +584 i +$ cd .. +$ cd .. +$ cd d +$ ls +4060174 j +8033020 d.log +5626152 d.ext +7214296 k"#; + + assert_eq!(part1(example), 95437); + assert_eq!(part2(example), 24933642); + } +}