days 7-10

This commit is contained in:
2022-12-11 23:52:03 +00:00
parent 474ad0a248
commit db450943a0
9 changed files with 355 additions and 0 deletions
+134
View File
@@ -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);
}