diff options
author | Martin Ashby <martin@ashbysoft.com> | 2022-12-07 21:30:24 +0000 |
---|---|---|
committer | Martin Ashby <martin@ashbysoft.com> | 2022-12-07 22:00:15 +0000 |
commit | 7383b348a746ac340e3058d733edc59a7c893e32 (patch) | |
tree | d80b93952ab8efedd12f61c8763ece4d0a120559 /src/day7.rs | |
parent | 745b6bfd5730a926a32c34d0b6e50a5685cbcddc (diff) | |
download | aoc2022-7383b348a746ac340e3058d733edc59a7c893e32.tar.gz aoc2022-7383b348a746ac340e3058d733edc59a7c893e32.tar.bz2 aoc2022-7383b348a746ac340e3058d733edc59a7c893e32.tar.xz aoc2022-7383b348a746ac340e3058d733edc59a7c893e32.zip |
day7
This one was a little trickier, as the obvious solution for navigating back up a tree is to keep a reference to the parent.
However that's essentially a doubly linked list which is a pain in the ass in Rust.
Instead, use a separate variable for the current 'key' into the tree
I'm not especially happy with the terminal processing as well, since after the 'ls' command we need to 'peek' at the next entry to see if the 'ls' has finished and we're onto a next command
I couldn't think of a very good way to do this except loops and loops.
Diffstat (limited to 'src/day7.rs')
-rw-r--r-- | src/day7.rs | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/src/day7.rs b/src/day7.rs new file mode 100644 index 0000000..e0df644 --- /dev/null +++ b/src/day7.rs @@ -0,0 +1,132 @@ +use std::{collections::HashMap}; + +// Making a recursive data structure in Rust is a pain in the ass. +// So don't bother, just link one way (nodes own their children) +// And we'll separately track our 'current working directory' with a +// vector of keys into the tree +#[derive(Debug)] +struct Node { + children: HashMap<String, Node>, + // Intrinsic size of the file at this location. + size: Option<u32>, + // Is the location a directory. Technically should be able to tell by presence/absence of children, but + // empty directories are a thing. + isdir: bool, +} + +impl Node { + fn new(isdir: bool) -> Node { + Node { + children: HashMap::new(), + size: None, + isdir: isdir, + } + } + fn set(&mut self, path: &Vec<&str>, size: Option<u32>, isdir: bool) { + let mut cn = self; + for ch in path { + cn = cn.children.entry((*ch).to_owned()).or_insert(Node::new(true)); + } + cn.size = size; + cn.isdir = isdir; + } + /** + * Returns a map of total, recursive directory sizes,by relative path from the current directory + * Empty string key is the current directory size + */ + fn dir_sizes(self) -> HashMap<String, u32> { + let mut res: HashMap<String, u32> = HashMap::new(); + let mut mysize: u32 = 0; + for (name, nn) in self.children { + if let Some(fz) = nn.size { + // It's a file, just add the size + mysize += fz; + } else { + // It's a directory, add the size _and_ all the entries with subdir prefixed + let child_ds = nn.dir_sizes(); + let child_sz = child_ds[""]; + mysize += child_sz; + for (cn, sz) in child_ds { + res.insert(format!("{}/{}", name, cn), sz); + } + } + } + res.insert("".to_owned(), mysize); + res + } +} + +pub fn run(input: String) { + let mut root = Node::new(true); + let mut cwd: Vec<&str>= vec![]; + let lines: Vec<&str> = input.lines().collect(); + let mut i = 0; + loop { + if i >= lines.len() { + break; + } + let line = lines[i]; + let toks: Vec<&str> = line.split_whitespace().collect(); + if toks[0] != "$" { + panic!("expected a command, got {}",line); + } + match toks[1] { + "cd" => { + i += 1; + let dirname = toks[2]; + if dirname == "/" { + cwd.clear(); + } else if dirname == ".." { + cwd.pop(); + } else { + cwd.push(dirname); + } + root.set(&cwd, None, true); + } + "ls" => { + i += 1; + loop { + if i >= lines.len() { + break; + } + let lsline = lines[i]; + let lstoks: Vec<&str> = lsline.split_whitespace().collect(); + if lstoks[0] == "$" { + // This is the next command, loop back to the top without incrementing! + break; + } + let (fsize, isdir) = if lstoks[0] == "dir" { + (None, true) + } else { + (Some(lstoks[0].parse().expect("filesize wasn't a u32!")), false) + }; + let fname = lstoks[1]; + cwd.push(fname); + root.set(&cwd, fsize, isdir); + cwd.pop(); + i += 1; + } + } + cmd => { + panic!("unknown command {}", cmd) + } + } + } + let ds = root.dir_sizes(); + // let mut tot: u32 = 0; + // for (_, sz) in ds { + // if sz <= 100000 { + // tot += sz; + // } + // } + // println!("Day 7: {}", tot); + let fs_size:u32 = 70000000; + let total_used = ds.get("").unwrap(); + let total_free = fs_size - total_used; + let update_size:u32 = 30000000; + let need_to_free = update_size - total_free; + let ddsz = ds.values() + .filter(|sz| { **sz >= need_to_free }) + .fold(fs_size, |acc, e| { acc.min(*e) }); + println!("Day 7: {}", ddsz); +}
\ No newline at end of file |