aoc2022/day7/src/main.rs
2022-12-07 15:50:56 +01:00

118 lines
3.7 KiB
Rust

use std::{fs::read_to_string, iter::Peekable, str::Lines};
#[derive(PartialEq, Debug)]
struct File {
name: String,
size: usize,
}
impl File {
fn size(&self) -> usize {
self.size
}
}
#[derive(PartialEq, Debug)]
struct Directory {
path: String,
files: Vec<File>,
}
fn size_of_dir(dirs: &[Directory], dir: &str) -> usize {
dirs.iter()
.filter_map(|d| {
if d.path.contains(dir) {
Some(d.files.iter().map(File::size).sum::<usize>())
} else {
None
}
})
.sum()
}
fn parse_command(
lines: &mut Peekable<Lines>,
cwd: &str,
directorys: &mut Vec<Directory>,
) -> Result<String, String> {
let command = lines.next().unwrap().split_whitespace().collect::<Vec<_>>();
if command.len() < 2 || command[0] != "$" {
return Err("first line is not a command".to_owned());
}
match command[1] {
"cd" => {
if command.len() != 3 {
return Err("cd needs exactly 1 argument".to_owned());
}
match command[2] {
"/" => Ok("/".to_owned()),
".." => {
if cwd == "/" {
Ok(cwd.to_owned())
} else {
let dirs = cwd.split_inclusive('/').collect::<Vec<_>>();
let nwd = dirs[..(dirs.len() - 1)]
.iter()
.fold(String::new(), |s, v| s + v);
Ok(nwd)
}
}
dir => Ok(cwd.to_owned() + dir + "/"),
}
}
"ls" => {
while let Some(line) = lines.peek() {
if line.split_whitespace().collect::<Vec<_>>().first() == Some(&"$") {
break;
}
let line = lines.next().unwrap();
let node = line.split_whitespace().collect::<Vec<_>>();
if node.len() != 2 {
return Err("ls needs two inputs per line".to_owned());
}
match node[0] {
"dir" => directorys.push(Directory {
path: cwd.to_owned() + node[1] + "/",
files: vec![],
}),
size => directorys
.iter_mut()
.find(|d| d.path == cwd)
.unwrap()
.files
.push(File {
name: node[1].to_owned(),
size: size.parse().expect("invalid Size"),
}),
}
}
Ok(cwd.to_owned())
}
_ => Err("unknown command".to_owned()),
}
}
fn main() {
const TOTAL_SPACE: usize = 70000000;
const NEEDED_FREE: usize = 30000000;
let input = read_to_string("input.txt").unwrap();
let mut lines = input.lines().peekable();
let mut dirs = vec![Directory {
path: "/".to_owned(),
files: vec![],
}];
let mut cwd = "/".to_owned();
while lines.peek().is_some() {
cwd = parse_command(&mut lines, &cwd, &mut dirs).expect("invalid input");
}
let sizes = dirs.iter().map(|d| size_of_dir(&dirs, &d.path));
let sol1: usize = sizes.clone().filter(|s| s < &100_000).sum();
println!("{sol1}");
let used = size_of_dir(&dirs, "/");
let free = TOTAL_SPACE - used;
let additional = NEEDED_FREE - free;
println!("{used} Bytes used, {free} Bytes free, {additional} Bytes need to be freed");
let sol2 = sizes.filter(|s| s >= &additional).min().unwrap();
println!("Deleting Directory with size {sol2}");
}