2022-7...

This commit is contained in:
Frederik Palmø 2023-05-30 15:04:49 +02:00
parent 61268dc5ec
commit 93d7537f66

169
src/bin/2022-7.rs Normal file
View File

@ -0,0 +1,169 @@
use eyes::parse;
use itertools::Itertools;
use std::{cell::RefCell, collections::HashMap, iter, rc::Rc};
fn main() {
let input = aoc::input!();
println!("part 1: {}", part1(&input));
println!("part 1: {}", part2(&input));
}
type RefNode = Rc<RefCell<Node>>;
#[derive(Default)]
struct Node {
size: u64,
children: HashMap<String, RefNode>,
parent: Option<RefNode>,
}
impl Node {
fn total_size(&self) -> u64 {
self.children
.values()
.map(|child| child.borrow().total_size())
.sum::<u64>()
+ self.size
}
}
fn all_dirs(n: RefNode) -> Box<dyn Iterator<Item = RefNode>> {
let children = n.borrow().children.values().cloned().collect::<Vec<_>>();
Box::new(
iter::once(n).chain(
children
.into_iter()
.filter_map(|c| {
if c.borrow().size == 0 {
Some(all_dirs(c))
} else {
None
}
})
.flatten(),
),
)
}
fn part1(input: &str) -> u64 {
let root = RefNode::default();
let mut node = root.clone();
for line in input.lines() {
match line {
l if l.starts_with("$ cd") => {
let dir = parse!(l, "$ cd {}", String);
match dir.as_str() {
"/" => continue,
".." => {
let parent = node.borrow().parent.clone().unwrap();
node = parent;
}
_ => {
let child = node.borrow_mut().children.entry(dir).or_default().clone();
node = child;
}
}
} // cd
l if l.starts_with("$ ls") => continue, // ls
l if l.starts_with("dir ") => {
// dir entry
let dir = parse!(l, "dir {}", String);
let entry = node.borrow_mut().children.entry(dir).or_default().clone();
entry.borrow_mut().parent = Some(node.clone());
}
l => {
// file entry
let (size, file) = parse!(l, "{} {}", u64, String);
let entry = node.borrow_mut().children.entry(file).or_default().clone();
entry.borrow_mut().size = size;
entry.borrow_mut().parent = Some(node.clone());
}
}
}
all_dirs(root)
.map(|d| d.borrow().total_size())
.filter(|&s| s <= 100_000)
.sum::<u64>()
}
fn part2(input: &str) -> u64 {
let root = RefNode::default();
let mut node = root.clone();
for line in input.lines() {
match line {
l if l.starts_with("$ cd") => {
let dir = parse!(l, "$ cd {}", String);
match dir.as_str() {
"/" => continue,
".." => {
let parent = node.borrow().parent.clone().unwrap();
node = parent;
}
_ => {
let child = node.borrow_mut().children.entry(dir).or_default().clone();
node = child;
}
}
} // cd
l if l.starts_with("$ ls") => continue, // ls
l if l.starts_with("dir ") => {
// dir entry
let dir = parse!(l, "dir {}", String);
let entry = node.borrow_mut().children.entry(dir).or_default().clone();
entry.borrow_mut().parent = Some(node.clone());
}
l => {
// file entry
let (size, file) = parse!(l, "{} {}", u64, String);
let entry = node.borrow_mut().children.entry(file).or_default().clone();
entry.borrow_mut().size = size;
entry.borrow_mut().parent = Some(node.clone());
}
}
}
let free_space = 70000000 - root.borrow().total_size();
all_dirs(root)
.map(|d| d.borrow().total_size())
.filter(|&s| s >= 30000000 - free_space)
.min()
.unwrap()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn examples() {
let example = r#"$ cd /
$ ls
dir a
14848514 b.txt
8504156 c.dat
dir d
$ cd a
$ ls
dir e
29116 f
2557 g
62596 h.lst
$ cd e
$ ls
584 i
$ cd ..
$ cd ..
$ cd d
$ ls
4060174 j
8033020 d.log
5626152 d.ext
7214296 k"#;
assert_eq!(part1(example), 95437);
assert_eq!(part2(example), 24933642);
}
}