You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
116 lines
3.3 KiB
Rust
116 lines
3.3 KiB
Rust
use std::cell::RefCell;
|
|
use std::collections::HashMap;
|
|
use std::rc::Rc;
|
|
|
|
#[derive(Debug)]
|
|
struct File {
|
|
name: String,
|
|
size: usize,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
struct Directory {
|
|
name: String,
|
|
files: Vec<File>,
|
|
directories: Vec<Rc<RefCell<Directory>>>,
|
|
parent: Option<Rc<RefCell<Directory>>>,
|
|
}
|
|
|
|
fn main() {
|
|
let contents = std::fs::read_to_string("data.txt").expect("Failed to read file");
|
|
let lines: Vec<&str> = contents.lines().collect();
|
|
let root = parse(&lines);
|
|
|
|
let mut sizes: HashMap<String, usize> = HashMap::new();
|
|
set_sizes(root, &mut sizes);
|
|
|
|
// Part 1
|
|
let sum = sizes
|
|
.to_owned()
|
|
.into_values()
|
|
.filter(|&x| x <= 100000usize)
|
|
.sum::<usize>();
|
|
println!("Sum: {:?}", sum);
|
|
|
|
// Part 2
|
|
let total = 70000000;
|
|
let needed = 30000000;
|
|
let used = sizes.get("").unwrap();
|
|
let unused = total - used;
|
|
let target = needed - unused;
|
|
let delete = sizes
|
|
.values()
|
|
.fold(total, |acc, &x| if x < acc && x > target { x } else { acc });
|
|
println!("Delete: {:?}", delete);
|
|
}
|
|
|
|
fn parse(lines: &Vec<&str>) -> Rc<RefCell<Directory>> {
|
|
let root = Rc::new(RefCell::new(Directory {
|
|
name: String::from("/"),
|
|
files: Vec::new(),
|
|
directories: Vec::new(),
|
|
parent: None,
|
|
}));
|
|
|
|
let mut dir = Rc::clone(&root);
|
|
|
|
for line in lines.get(1..lines.len()).unwrap() {
|
|
let parts = line.split(" ").collect::<Vec<&str>>();
|
|
|
|
match parts.as_slice() {
|
|
["$", "ls"] => (), // ignore. we'll match on dirs and files below
|
|
["dir", _] => (), // ignore. we'll add it when we cd into it
|
|
[size, name] => {
|
|
dir.borrow_mut().files.push(File {
|
|
name: String::from(*name),
|
|
size: size.parse().unwrap(),
|
|
});
|
|
}
|
|
["$", "cd", ".."] => {
|
|
// go up a directory by setting dir to the parent
|
|
let temp = Rc::clone(&dir);
|
|
dir = Rc::clone(temp.borrow().parent.as_ref().unwrap());
|
|
}
|
|
["$", "cd", path] => {
|
|
// go down a directory by creating one and pointing dir at it
|
|
let new_dir = Rc::new(RefCell::new(Directory {
|
|
name: String::from(*path),
|
|
files: Vec::new(),
|
|
directories: Vec::new(),
|
|
parent: Some(Rc::clone(&dir)),
|
|
}));
|
|
let temp = Rc::clone(&new_dir);
|
|
dir.borrow_mut().directories.push(temp);
|
|
dir = new_dir;
|
|
}
|
|
_ => (),
|
|
};
|
|
}
|
|
|
|
return root;
|
|
}
|
|
|
|
fn get_path(dir: Rc<RefCell<Directory>>) -> String {
|
|
match &dir.borrow().parent {
|
|
Some(d) => dir.borrow().name.to_string() + "/" + &get_path(d.to_owned()),
|
|
None => "".to_string(),
|
|
}
|
|
}
|
|
|
|
fn set_sizes(dir: Rc<RefCell<Directory>>, hash: &mut HashMap<String, usize>) -> usize {
|
|
let d = dir.borrow();
|
|
let mut size = 0;
|
|
|
|
// add all the file sizes to this dir's size
|
|
d.files.iter().for_each(|file| size += file.size);
|
|
|
|
// add all the sub dirs' size to this dir's size
|
|
d.directories
|
|
.iter()
|
|
.for_each(|child| size += set_sizes(Rc::clone(child), hash));
|
|
|
|
let path = get_path(dir.to_owned());
|
|
hash.insert(path, size);
|
|
size
|
|
}
|