77 lines
2.1 KiB
Rust
77 lines
2.1 KiB
Rust
#![warn(clippy::pedantic)]
|
|
|
|
use std::{
|
|
collections::HashMap,
|
|
hash::Hash,
|
|
io::{stdin, Read},
|
|
path::{Path, PathBuf},
|
|
};
|
|
|
|
use aoc::*;
|
|
|
|
fn main() {
|
|
let mut data = String::new();
|
|
stdin().read_to_string(&mut data).unwrap();
|
|
|
|
let mut cwd = PathBuf::new();
|
|
cwd.push("/");
|
|
let mut dirs: HashMap<PathBuf, usize> = HashMap::new();
|
|
|
|
for line in data.lines() {
|
|
if let Some(command) = line.strip_prefix("$ ") {
|
|
let mut args = command.split_whitespace();
|
|
let command = args.next().unwrap();
|
|
match command {
|
|
"ls" => {
|
|
dirs.remove(&cwd);
|
|
}
|
|
"cd" => {
|
|
let dir = args.next().unwrap();
|
|
match dir {
|
|
".." => assert!(cwd.pop()),
|
|
path => cwd.push(path),
|
|
}
|
|
}
|
|
_ => panic!("unknown command {command}"),
|
|
}
|
|
} else {
|
|
let (size, _name) = line.split_once(' ').unwrap();
|
|
if size == "dir" {
|
|
// skip
|
|
} else {
|
|
let size: usize = size.parse().unwrap();
|
|
*dirs.entry(cwd.clone()).or_default() += size;
|
|
}
|
|
}
|
|
}
|
|
|
|
let mut dirs_recursive: HashMap<&Path, usize> = HashMap::new();
|
|
for (dir, size) in &dirs {
|
|
for parent in std::iter::successors(Some(&**dir), |dir| dir.parent()) {
|
|
*dirs_recursive.entry(parent).or_default() += size;
|
|
}
|
|
}
|
|
|
|
println!(
|
|
"{}",
|
|
dirs_recursive
|
|
.values()
|
|
.filter(|&&s| s <= 100_000)
|
|
.sum::<usize>()
|
|
);
|
|
|
|
const TOTAL_SPACE: usize = 70_000_000;
|
|
const REQUIRED_SPACE: usize = 30_000_000;
|
|
|
|
let unused = TOTAL_SPACE - dirs_recursive[&*PathBuf::from("/")];
|
|
let to_free = REQUIRED_SPACE - unused;
|
|
let mut sizes: Vec<_> = dirs_recursive.values().copied().collect();
|
|
sizes.sort_unstable();
|
|
let size = match sizes.binary_search(&to_free) {
|
|
Ok(i) => sizes[i],
|
|
Err(larger) => sizes[larger],
|
|
};
|
|
|
|
println!("{}", size);
|
|
}
|