Solve day07
This commit is contained in:
parent
adda8cb807
commit
96869bff2f
9
Cargo.lock
generated
9
Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -8,3 +8,4 @@ build = true
|
|||
app = true
|
||||
|
||||
[dependencies]
|
||||
ego-tree = "0.6.2"
|
||||
|
|
1022
day07/input
Normal file
1022
day07/input
Normal file
File diff suppressed because it is too large
Load diff
23
day07/input.test
Normal file
23
day07/input.test
Normal 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
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue