Solve day07

This commit is contained in:
Malte Tammena 2022-12-07 09:58:07 +01:00
parent adda8cb807
commit 96869bff2f
5 changed files with 1252 additions and 2 deletions

9
Cargo.lock generated
View file

@ -117,6 +117,9 @@ dependencies = [
[[package]]
name = "day07"
version = "0.1.0"
dependencies = [
"ego-tree",
]
[[package]]
name = "day08"
@ -186,6 +189,12 @@ version = "0.1.0"
name = "day24"
version = "0.1.0"
[[package]]
name = "ego-tree"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a68a4904193147e0a8dec3314640e6db742afd5f6e634f428a6af230d9b3591"
[[package]]
name = "errno"
version = "0.2.8"

View file

@ -8,3 +8,4 @@ build = true
app = true
[dependencies]
ego-tree = "0.6.2"

1022
day07/input Normal file

File diff suppressed because it is too large Load diff

23
day07/input.test Normal file
View file

@ -0,0 +1,23 @@
$ 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

View file

@ -1,3 +1,198 @@
fn main() {
println!("Hello, world!");
use ego_tree::NodeId;
use std::{
fs::File,
io::{BufRead, BufReader},
};
type NodeMut<'t> = ego_tree::NodeMut<'t, Node>;
type NodeRef<'t> = ego_tree::NodeRef<'t, Node>;
type Tree = ego_tree::Tree<Node>;
#[derive(Debug, Default, PartialEq, Eq)]
enum SolvePuzzle {
First,
#[default]
Second,
}
#[derive(Debug)]
struct Node {
label: String,
size: Option<usize>,
dir: bool,
}
struct TreeParser {
tree: Tree,
curr_node: NodeId,
reading_dir_list: bool,
}
impl TreeParser {
pub fn new() -> Self {
let tree = Tree::new(Node {
label: String::from("/"),
size: None,
dir: true,
});
Self {
curr_node: tree.root().id(),
tree,
reading_dir_list: false,
}
}
fn read(&mut self, line: &str) {
self.reading_dir_list &= !line.starts_with("$");
if line == "$ cd /" {
self.curr_node = self.tree.root().id();
} else if line == "$ cd .." {
let node = self.curr_node();
self.curr_node = node.parent().unwrap().id();
} else if line.starts_with("$ cd ") {
let node = self.curr_node();
let target = &line[5..];
let target = node
.children()
.find(|child| child.value().label == target)
.expect("Cd target exists");
self.curr_node = target.id();
} else if line == "$ ls" {
self.reading_dir_list = true;
} else if self.reading_dir_list == true && line.starts_with("dir ") {
let label = &line[4..];
let mut node = self.curr_node_mut();
node.append(Node {
label: label.to_owned(),
size: None,
dir: true,
});
} else if self.reading_dir_list {
let (size, label) = line.split_once(' ').expect("A dir list entry");
let mut node = self.curr_node_mut();
node.append(Node {
label: label.to_owned(),
size: Some(size.parse().expect("Filesize is number")),
dir: false,
});
} else {
panic!("What? {:?}", line);
}
}
fn curr_node(&self) -> NodeRef {
self.tree.get(self.curr_node).unwrap()
}
fn curr_node_mut(&mut self) -> NodeMut {
self.tree.get_mut(self.curr_node).unwrap()
}
fn finish(mut self) -> Tree {
let node_id = self.tree.root().id();
fill_size(&mut self.tree, node_id);
self.tree
}
}
fn fill_size(tree: &mut Tree, node_id: NodeId) {
let node_ref = tree.get(node_id);
let missing: Vec<_> = {
node_ref
.unwrap()
.children()
.filter(|child| child.value().size.is_none())
.map(|child| child.id())
.collect()
};
for miss in missing {
fill_size(tree, miss);
}
let node_ref = tree.get(node_id);
let size = node_ref
.unwrap()
.children()
.map(|child| child.value().size)
.map(Option::unwrap)
.sum();
tree.get_mut(node_id).unwrap().value().size = Some(size);
}
fn solve_first_puzzle<R: BufRead>(reader: R) -> usize {
let parser = reader
.lines()
.map(Result::unwrap)
.fold(TreeParser::new(), |mut parser, line| {
parser.read(&line);
parser
});
let tree = parser.finish();
tree.nodes()
.map(|node_ref| node_ref.value())
.filter(|node| node.dir == true)
.map(|node| node.size.unwrap())
.filter(|&size| size <= 100000)
.sum()
}
fn solve_second_puzzle<R: BufRead>(reader: R) -> usize {
const REQUIRED_SIZE: usize = 30_000_000;
const TOTAL: usize = 70_000_000;
let parser = reader
.lines()
.map(Result::unwrap)
.fold(TreeParser::new(), |mut parser, line| {
parser.read(&line);
parser
});
let tree = parser.finish();
let root_size = tree.root().value().size.unwrap();
let free = TOTAL - root_size;
let missing = REQUIRED_SIZE.saturating_sub(free);
tree.nodes()
.map(|node_ref| node_ref.value())
.filter(|node| node.dir == true)
.map(|node| node.size)
.map(Option::unwrap)
.filter(|&size| size >= missing)
.min()
.expect("At least one node")
}
fn main() {
let mut args = ::std::env::args().skip(1);
let file = args.next().unwrap_or_else(|| String::from("./input"));
let solve = args
.next()
.map(|arg| match arg.as_str() {
"first" => SolvePuzzle::First,
"second" => SolvePuzzle::Second,
_ => unreachable!(),
})
.unwrap_or_default();
let reader = BufReader::new(File::open(file).expect("Opening file"));
let solution = match solve {
SolvePuzzle::First => solve_first_puzzle(reader),
SolvePuzzle::Second => solve_second_puzzle(reader),
};
println!("{}", solution);
}
#[cfg(test)]
mod tests {
use std::io::Cursor;
use super::*;
#[test]
fn example_on_first() {
let reader = Cursor::new(include_str!("../input.test"));
assert_eq!(solve_first_puzzle(reader), 95437);
}
#[test]
fn example_on_second() {
let reader = Cursor::new(include_str!("../input.test"));
assert_eq!(solve_second_puzzle(reader), 24933642);
}
}