diff --git a/2022/Cargo.lock b/2022/Cargo.lock index a1ea46f..c1c2651 100644 --- a/2022/Cargo.lock +++ b/2022/Cargo.lock @@ -23,6 +23,7 @@ version = "0.1.0" dependencies = [ "anyhow", "itertools", + "path-absolutize", "regex", ] @@ -47,6 +48,30 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "once_cell" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" + +[[package]] +name = "path-absolutize" +version = "3.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f1d4993b16f7325d90c18c3c6a3327db7808752db8d208cea0acee0abd52c52" +dependencies = [ + "path-dedot", +] + +[[package]] +name = "path-dedot" +version = "3.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a81540d94551664b72b72829b12bd167c73c9d25fbac0e04fafa8023f7e4901" +dependencies = [ + "once_cell", +] + [[package]] name = "regex" version = "1.7.0" diff --git a/2022/Cargo.toml b/2022/Cargo.toml index c43c017..3daf7b5 100644 --- a/2022/Cargo.toml +++ b/2022/Cargo.toml @@ -6,4 +6,5 @@ edition = "2021" [dependencies] anyhow = "1.0.66" itertools = "0.10.5" +path-absolutize = "3.0.14" regex = "1.7.0" diff --git a/2022/src/bin/day07.rs b/2022/src/bin/day07.rs new file mode 100644 index 0000000..91e712c --- /dev/null +++ b/2022/src/bin/day07.rs @@ -0,0 +1,147 @@ +use std::{ + collections::HashMap, + path::{Path, PathBuf}, +}; + +use path_absolutize::Absolutize; + +const INPUT: &str = include_str!("../../input/day07.txt"); + +fn main() { + let mut cwd: PathBuf = "/".parse().unwrap(); // Because where else would we be? + + let mut fs: HashMap = HashMap::new(); + + for block in parse(INPUT) { + let cmdline: Vec<&str> = split_words(&block.cmd); + + let knowledge: Knowledge; + (cwd, knowledge) = match cmdline[0] { + "cd" => cd(&cwd, cmdline[1]), + "ls" => ls(&cwd, block.out), + other => panic!("{}", other), + }; + + for (path, size) in &knowledge { + let Some(size) = size else { continue }; + let old = fs.insert(path.to_path_buf(), *size); + + assert!(old.is_none()); + } + } + + let du = du(fs); + + let dirs = du.iter().collect::>(); + + let part1: u64 = dirs + .iter() + .cloned() + .map(|(_path, size)| *size) + .filter(|size| size <= &100_000) + .sum(); + + println!("Part 1: {}", part1); + + let total = 70_000_000; + let needed = 30_000_000; + + let root: PathBuf = "/".parse().unwrap(); + let used = du.get(&root).unwrap(); + let unused = total - used; + let to_free = needed - unused; + + let mut freeable = dirs + .iter() + .cloned() + .map(|(_path, size)| *size) + .filter(|size| size > &to_free) + .collect::>(); + + freeable.sort(); + + let part2 = freeable[0]; + + println!("Part 2: {}", part2); +} + +fn du(fs: HashMap) -> HashMap { + let mut dirs = HashMap::new(); + for (path, size) in fs { + let mut dir = path; + while dir.pop() { + dirs.entry(dir.to_path_buf()) + .and_modify(|s| *s += size) + .or_insert(size); + } + } + dirs +} + +type Size = u64; +type Knowledge = Vec<(PathBuf, Option)>; + +fn cd(cwd: &Path, arg: &str) -> (PathBuf, Knowledge) { + let cwd = cwd.join(arg); + let cwd = cwd.absolutize().unwrap(); + (cwd.to_path_buf(), Default::default()) +} + +fn ls(cwd: &Path, output: String) -> (PathBuf, Knowledge) { + let mut knowledge: Knowledge = vec![]; + + for line in split_lines(&output) { + let words = split_words(line); + + let size: Option = words[0].parse::().ok(); + let path = cwd.join(words[1]).to_path_buf(); + + knowledge.push((path, size)); + } + (cwd.into(), knowledge) +} + +#[derive(Debug, Clone)] +struct Block { + cmd: String, + out: String, +} + +fn parse(input: &str) -> Vec { + let mut blocks = vec![]; + + let lines = split_lines(input); + + let mut block: Option = None; + + for line in lines { + if line.get(0..1) == Some("$") { + if let Some(block) = block { + blocks.push(block.clone()); + } + + block = Some(Block { + cmd: line.get(("$ ".len())..).unwrap().to_string(), + out: "".to_string(), + }); + } else { + let mut b = block.unwrap(); + b.out += line; + b.out += "\n"; + block = Some(b); + } + } + if let Some(block) = block { + blocks.push(block); + } + + blocks +} + +fn split_lines(s: &str) -> Vec<&str> { + s.trim_end().split('\n').collect() +} + +fn split_words(s: &str) -> Vec<&str> { + s.split(' ').collect() +}