Created
December 7, 2022 18:38
-
-
Save saolsen/cd873808264a3c613d17de6db3a0e5b2 to your computer and use it in GitHub Desktop.
aoc 2022 day07
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::{collections::HashMap, iter::Peekable, str::Split}; | |
#[derive(Debug)] | |
struct Dir<'a> { | |
path: Vec<&'a str>, | |
files: HashMap<&'a str, File<'a>>, | |
} | |
#[derive(Debug)] | |
struct File<'a> { | |
name: &'a str, | |
size: usize, | |
} | |
struct Shell<'a> { | |
dirs: HashMap<Vec<&'a str>, Dir<'a>>, | |
lines: Peekable<Split<'a, &'a str>>, | |
cwd: Vec<&'a str>, | |
} | |
impl<'a> Shell<'a> { | |
pub fn new(input: &'a str) -> Self { | |
let lines = input.split("\n").peekable(); | |
let mut dirs = HashMap::new(); | |
dirs.insert( | |
vec!["/"], | |
Dir { | |
path: vec!["/"], | |
files: HashMap::new(), | |
}, | |
); | |
let cwd = vec![]; | |
Shell { dirs, lines, cwd } | |
} | |
pub fn command(&mut self) -> bool { | |
if let Some(line) = self.lines.next() { | |
let mut split = line.split(" "); | |
assert_eq!(split.next(), Some("$")); | |
let command = split.next().unwrap(); | |
match command { | |
"cd" => { | |
let dir_name = split.next().unwrap(); | |
if dir_name == ".." { | |
self.cwd.pop(); | |
} else { | |
self.cwd.push(dir_name); | |
} | |
} | |
"ls" => { | |
//let current_dir = &mut self.dirs[self.cwd]; | |
let mut new_children = vec![]; | |
let mut new_files = vec![]; | |
loop { | |
if let Some(next_line) = self.lines.peek() { | |
if next_line.starts_with("$") { | |
break; | |
} | |
} else { | |
break; | |
} | |
let result = self.lines.next().unwrap(); | |
let mut parts = result.split(" "); | |
let a = parts.next().unwrap(); | |
let b = parts.next().unwrap(); | |
if a == "dir" { | |
let mut path = self.cwd.clone(); | |
path.push(b); | |
if !self.dirs.contains_key(&path) { | |
new_children.push(Dir { | |
path, | |
files: HashMap::new(), | |
}) | |
} | |
} else { | |
if !self.dirs.get(&self.cwd).unwrap().files.contains_key(b) { | |
new_files.push(File { | |
name: b, | |
size: a.parse().unwrap(), | |
}); | |
} | |
} | |
} | |
for c in new_children { | |
self.dirs.insert(c.path.clone(), c); | |
} | |
for f in new_files { | |
let cwd = self.dirs.get_mut(&self.cwd).unwrap(); | |
cwd.files.insert(f.name, f); | |
} | |
} | |
_ => unimplemented!(), | |
} | |
true | |
} else { | |
false | |
} | |
} | |
pub fn dir_sizes(&self) -> HashMap<Vec<&'a str>, usize> { | |
let mut result = HashMap::new(); | |
for path in self.dirs.keys() { | |
let mut sum = 0; | |
for (p, dir) in &self.dirs { | |
if p.starts_with(path) { | |
for (_, f) in &dir.files { | |
sum += f.size; | |
} | |
} | |
} | |
result.insert(path.clone(), sum); | |
} | |
result | |
} | |
pub fn run(&mut self) { | |
while self.command() {} | |
} | |
} | |
fn main() { | |
let mut shell = Shell::new(include_str!("day07_input.txt")); | |
shell.run(); | |
let sizes = shell.dir_sizes(); | |
// part 1 | |
let mut total = 0; | |
for (_, s) in &sizes { | |
if *s <= 100000 { | |
total += *s; | |
} | |
} | |
eprintln!("total: {total}"); | |
// part 2 | |
let disk_space = 70000000; | |
let needed_free = 30000000; | |
let size_of_root = sizes.get(&vec!["/"]).unwrap(); | |
let size_free = disk_space - size_of_root; | |
let still_need_to_free = needed_free - size_free; | |
let mut min_big_enough = usize::MAX; | |
for (_, s) in &sizes { | |
if *s > still_need_to_free && *s < min_big_enough { | |
min_big_enough = *s; | |
} | |
} | |
eprintln!("delete size: {min_big_enough}"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment