2022-7...
This commit is contained in:
parent
61268dc5ec
commit
93d7537f66
1 changed files with 169 additions and 0 deletions
169
src/bin/2022-7.rs
Normal file
169
src/bin/2022-7.rs
Normal 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);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue