day 7
This commit is contained in:
parent
094ab63ceb
commit
933cdbfd19
|
@ -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
184
src/days/day7.rs
Normal 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
|
||||
}
|
|
@ -7,6 +7,7 @@ mod days {
|
|||
mod day4;
|
||||
mod day5;
|
||||
mod day6;
|
||||
mod day7;
|
||||
}
|
||||
|
||||
aoc_lib! { year = 2022 }
|
||||
|
|
Loading…
Reference in a new issue