use std::env; use std::fs::File; use std::io::{self, BufRead}; use std::collections::HashMap; fn main() { let file = File::open(&env::args().nth(1).unwrap()).unwrap(); let mut lines = io::BufReader::new(file).lines(); let mut tree = DirTree::new(); let mut cwd = 0; loop { let tokens: Vec<_> = if let Some(Ok(l)) = lines.next() { l.split_whitespace().map(String::from).collect() } else { break; }; if tokens[0] == "$" { if tokens[1] == "cd" { if tokens[2] == ".." { cwd = tree.inodes[cwd].parent.unwrap(); } else if tokens[2] == "/" { cwd = 0; } else { let subdir = tree.inodes[cwd].subdirs[&tokens[2]]; cwd = subdir; } } else if tokens[1] == "ls" { continue; } } else if tokens[0] == "dir" { tree.add_subdir_to(cwd, tokens[1].clone()); } else { tree.add_file_to( cwd, tokens[1].clone(), tokens[0].parse::().unwrap()); } } let sum: usize = (0..tree.inodes.len()) .map(|inode| tree.size_of(inode)) .filter(|size| *size <= 100000) .sum(); println!("{:?}", sum); } #[derive(Debug)] struct Dir { pub files: HashMap, // file name and size pub subdirs: HashMap, // dir name and index into arena pub parent: Option, // index into arena } #[derive(Debug)] struct DirTree { inodes: Vec, } impl DirTree { fn new() -> Self { let newdir = Dir { files: HashMap::new(), subdirs: HashMap::new(), parent: None, }; DirTree { inodes: vec![newdir] } } fn add_subdir_to(&mut self, idx: usize, name: String) { let newidx = self.inodes.len(); let newdir = Dir { files: HashMap::new(), subdirs: HashMap::new(), parent: Some(idx), }; self.inodes.push(newdir); self.inodes[idx].subdirs.insert(name, newidx); } fn add_file_to(&mut self, idx: usize, name: String, size: usize) { self.inodes[idx].files.insert(name, size); } fn size_of(&self, inode: usize) -> usize { let size_files: usize = self.inodes[inode].files.values().sum(); let size_dirs: usize = self.inodes[inode].subdirs.values() .fold(0, |acc, subdir_inode| acc + self.size_of(*subdir_inode)); size_files + size_dirs } }