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

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
}