This commit is contained in:
missing 2022-12-07 14:13:48 -06:00
parent 094ab63ceb
commit 933cdbfd19
3 changed files with 186 additions and 0 deletions

View File

@ -9,3 +9,4 @@ edition = "2021"
aoc-runner = "0.3.0"
aoc-runner-derive = "0.3.0"
itertools = "0.10.5"
slotmap = "1.0.6"

184
src/days/day7.rs Normal file
View File

@ -0,0 +1,184 @@
use std::collections::HashMap;
use aoc_runner_derive::{aoc, aoc_generator};
use slotmap::{new_key_type, SlotMap};
new_key_type! {
struct FsKey;
}
struct Fs {
root_dir: FsKey,
entries: SlotMap<FsKey, FsEntry>,
}
impl Fs {
fn new() -> Self {
let mut map = SlotMap::with_key();
let root_key = map.insert(FsEntry {
parent: None,
size: 0,
kind: FsEntryKind::Dir(HashMap::new()),
});
Self {
entries: map,
root_dir: root_key,
}
}
fn visit_children(&self, root: FsKey, mut f: impl FnMut(&FsEntry)) {
self.__visit_children(root, &mut f);
}
fn __visit_children(&self, root: FsKey, f: &mut impl FnMut(&FsEntry)) {
let entry = self.get(root);
f(entry);
if let FsEntryKind::Dir(children) = &entry.kind {
for &child in children.values() {
self.__visit_children(child, &mut *f);
}
}
}
fn visit_parents_mut(&mut self, root: FsKey, mut f: impl FnMut(&mut FsEntry)) {
let entry = self.get_mut(root);
f(entry);
if let Some(parent_key) = entry.parent {
self.visit_parents_mut(parent_key, f);
}
}
fn add(&mut self, name: String, entry: FsEntry) -> FsKey {
let entry_size = entry.size;
let current_dir = entry.parent.unwrap();
let entry_key = self.entries.insert(entry);
let current = self.get_mut(current_dir);
let FsEntryKind::Dir(children) = &mut current.kind else {
panic!("not a directory");
};
assert!(!children.contains_key(&name));
children.insert(name, entry_key);
self.visit_parents_mut(current_dir, |v| {
v.size += entry_size;
});
entry_key
}
fn get(&self, key: FsKey) -> &FsEntry {
self.entries.get(key).unwrap()
}
fn get_mut(&mut self, key: FsKey) -> &mut FsEntry {
self.entries.get_mut(key).unwrap()
}
}
struct FsEntry {
parent: Option<FsKey>,
size: u64,
kind: FsEntryKind,
}
enum FsEntryKind {
File,
Dir(HashMap<String, FsKey>),
}
#[aoc_generator(day7)]
fn generator(input: &str) -> Fs {
let mut fs = Fs::new();
let mut current_dir = fs.root_dir;
let mut lines = input.lines().peekable();
while let Some(l) = lines.next() {
let l = l.strip_prefix("$ ").unwrap();
if let Some(name) = l.strip_prefix("cd") {
let name = name.trim();
if name == "/" {
current_dir = fs.root_dir;
} else if name == ".." {
current_dir = fs.get(current_dir).parent.unwrap();
} else {
let FsEntryKind::Dir(children) = &fs.get(current_dir).kind else {
panic!("not a directory");
};
current_dir = *children.get(name).unwrap();
}
} else if l.trim() == "ls" {
while let Some(l) = lines.next_if(|v| !v.starts_with('$')) {
let (size_or_dir, name) = l.split_once(' ').unwrap();
let name = name.trim().to_owned();
let entry = if size_or_dir == "dir" {
FsEntry {
parent: Some(current_dir),
size: 0,
kind: FsEntryKind::Dir(HashMap::new()),
}
} else {
FsEntry {
parent: Some(current_dir),
size: size_or_dir.parse().unwrap(),
kind: FsEntryKind::File,
}
};
fs.add(name, entry);
}
}
}
fs
}
#[aoc(day7, part1)]
fn part1_indexing(fs: &Fs) -> u64 {
let mut res = 0;
fs.visit_children(fs.root_dir, |f| {
if let FsEntryKind::Dir(_) = f.kind {
if f.size <= 100000 {
res += f.size;
}
}
});
res
}
#[aoc(day7, part2)]
fn part2(fs: &Fs) -> u64 {
const TOTAL_SPACE: u64 = 70_000_000;
const NEEDED_FREE_SPACE: u64 = 30_000_000;
let used_space = fs.get(fs.root_dir).size;
let free_space = TOTAL_SPACE - used_space;
let need_to_free = NEEDED_FREE_SPACE - free_space;
let mut res = u64::MAX;
fs.visit_children(fs.root_dir, |f| {
if let FsEntryKind::Dir(_) = f.kind {
if f.size >= need_to_free && f.size < res {
res = f.size;
}
}
});
res
}

View File

@ -7,6 +7,7 @@ mod days {
mod day4;
mod day5;
mod day6;
mod day7;
}
aoc_lib! { year = 2022 }