days 7-10
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
use rustc_hash::FxHashMap;
|
||||
use std::path::Path;
|
||||
|
||||
const TOTAL_SPACE: usize = 70_000_000;
|
||||
const REQUIRED_SPACE: usize = 30_000_000;
|
||||
|
||||
fn main() {
|
||||
let s = std::fs::read_to_string("/dev/stdin").unwrap();
|
||||
let mut commands = s.split("$ ");
|
||||
commands.next(); // chuck out first empty string
|
||||
let mut pwd: Option<String> = None;
|
||||
let mut file_tree: FxHashMap<String, Vec<(String, Option<usize>)>> = FxHashMap::default();
|
||||
let mut dir_totals: FxHashMap<String, usize> = FxHashMap::default();
|
||||
|
||||
for command in commands {
|
||||
let lines = command.lines().collect::<Vec<&str>>();
|
||||
let cmd = lines.first().unwrap();
|
||||
let args = cmd.split(' ').collect::<Vec<&str>>();
|
||||
let cmd = args.first().unwrap();
|
||||
let args = args.get(1..).unwrap();
|
||||
|
||||
match *cmd {
|
||||
"cd" => cd(&mut pwd, args),
|
||||
"ls" => ls(
|
||||
&pwd,
|
||||
lines.get(1..).unwrap(),
|
||||
&mut file_tree,
|
||||
&mut dir_totals,
|
||||
),
|
||||
invalid => panic!("unexpected command: {:?}", invalid),
|
||||
}
|
||||
}
|
||||
|
||||
for directory in file_tree.iter() {
|
||||
let mut total = 0;
|
||||
let dir_str = Path::new(&directory.0);
|
||||
|
||||
if dir_str.file_name().is_some()
|
||||
&& dir_totals.contains_key(&dir_str.to_str().unwrap().to_string())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for item in directory.1.iter() {
|
||||
if let Some(file_size) = item.1 {
|
||||
total += file_size;
|
||||
}
|
||||
}
|
||||
dir_totals.insert(directory.0.to_string(), total);
|
||||
}
|
||||
|
||||
let mut dirs = file_tree.iter().collect::<Vec<_>>();
|
||||
dirs.sort_by(|a, b| {
|
||||
b.0.split('/')
|
||||
.count()
|
||||
.cmp(&a.0.split('/').count())
|
||||
.then(b.0.len().cmp(&a.0.len()))
|
||||
});
|
||||
for dir in dirs.iter() {
|
||||
for sub_dir in dir.1.iter().filter(|dir| dir.1.is_none()) {
|
||||
let balls = (dir.0.to_owned() + &sub_dir.0.replace("dir ", "/")).replace("//", "/");
|
||||
|
||||
dir_totals.insert(
|
||||
dir.0.to_owned(),
|
||||
*dir_totals.get(&dir.0.to_owned()).unwrap() + *dir_totals.get(&balls).unwrap(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let sum = dir_totals
|
||||
.iter()
|
||||
.filter(|dir| dir.1 < &100000)
|
||||
.fold(0, |total, dir| total + dir.1);
|
||||
|
||||
let free_space = TOTAL_SPACE - dir_totals.get("/").unwrap();
|
||||
let minimum_required = REQUIRED_SPACE - free_space;
|
||||
|
||||
let mut deletable: Vec<(&String, &usize)> = dir_totals
|
||||
.iter()
|
||||
.filter(|dir| dir.1 >= &minimum_required)
|
||||
.collect();
|
||||
deletable.sort_by(|a, b| a.1.cmp(b.1));
|
||||
println!("P1: {} P2: {}", sum, deletable.first().unwrap().1);
|
||||
}
|
||||
|
||||
fn cd(pwd: &mut Option<String>, args: &[&str]) {
|
||||
let path_str = String::new();
|
||||
let path = pwd.as_ref().unwrap_or(&path_str);
|
||||
let dir = args.first().expect("cd requries an arg").to_string();
|
||||
if dir == ".." {
|
||||
let mut split_path = path.split('/').collect::<Vec<&str>>();
|
||||
split_path.pop();
|
||||
if split_path.len() == 1 {
|
||||
split_path.push("");
|
||||
}
|
||||
*pwd = Some(split_path.join("/"));
|
||||
} else if !path.is_empty() && path != "/" {
|
||||
*pwd = Some(path.to_owned() + "/" + &dir);
|
||||
} else {
|
||||
*pwd = Some(path.to_owned() + &dir);
|
||||
}
|
||||
}
|
||||
|
||||
fn ls(
|
||||
pwd: &Option<String>,
|
||||
lines: &[&str],
|
||||
file_tree: &mut FxHashMap<String, Vec<(String, Option<usize>)>>,
|
||||
dir_totals: &mut FxHashMap<String, usize>,
|
||||
) {
|
||||
let mut contents: Vec<(String, Option<usize>)> = Vec::new();
|
||||
let mut contains_dirs = false; // if no inner dirs, work out total here
|
||||
|
||||
for line in lines {
|
||||
if line.starts_with("dir ") {
|
||||
contents.push((line.to_string(), None));
|
||||
contains_dirs = true;
|
||||
continue;
|
||||
}
|
||||
let file_data = line.split_once(' ').unwrap();
|
||||
let (file_size, file_name) = (
|
||||
file_data.0.parse::<usize>().unwrap(),
|
||||
file_data.1.to_string(),
|
||||
);
|
||||
contents.push((file_name, Some(file_size)));
|
||||
}
|
||||
if !contains_dirs {
|
||||
let mut total = 0;
|
||||
for (_, size) in contents.iter() {
|
||||
total += size.unwrap();
|
||||
}
|
||||
dir_totals.insert(pwd.as_ref().unwrap().to_string(), total);
|
||||
}
|
||||
file_tree.insert(pwd.as_ref().unwrap().to_string(), contents);
|
||||
}
|
||||
Reference in New Issue
Block a user