Improve day07
This commit is contained in:
parent
96869bff2f
commit
7ad37b1a89
9
Cargo.lock
generated
9
Cargo.lock
generated
|
@ -117,9 +117,6 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "day07"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ego-tree",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "day08"
|
||||
|
@ -189,12 +186,6 @@ 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,4 +8,3 @@ build = true
|
|||
app = true
|
||||
|
||||
[dependencies]
|
||||
ego-tree = "0.6.2"
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
use ego_tree::NodeId;
|
||||
#![feature(binary_heap_into_iter_sorted)]
|
||||
|
||||
use std::{
|
||||
cmp::Reverse,
|
||||
collections::BinaryHeap,
|
||||
fs::File,
|
||||
io::{BufRead, BufReader},
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
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,
|
||||
|
@ -16,147 +16,95 @@ enum SolvePuzzle {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Node {
|
||||
label: String,
|
||||
size: Option<usize>,
|
||||
dir: bool,
|
||||
struct Collector<Ext: CollectorExt> {
|
||||
pwd: PathBuf,
|
||||
sums: Vec<usize>,
|
||||
ext: Ext,
|
||||
}
|
||||
|
||||
struct TreeParser {
|
||||
tree: Tree,
|
||||
curr_node: NodeId,
|
||||
reading_dir_list: bool,
|
||||
trait CollectorExt: Default {
|
||||
fn change_directory_up(&mut self, dir_size: usize);
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Default)]
|
||||
struct PartOne {
|
||||
small_dirs_sum: usize,
|
||||
}
|
||||
|
||||
fn read(&mut self, line: &str) {
|
||||
self.reading_dir_list &= !line.starts_with("$");
|
||||
#[derive(Debug, Default)]
|
||||
struct PartTwo {
|
||||
smallest_relevant_dirs: BinaryHeap<Reverse<usize>>,
|
||||
}
|
||||
|
||||
impl<Ext: CollectorExt> Collector<Ext> {
|
||||
pub fn push_line<S: AsRef<str>>(&mut self, line: S) {
|
||||
let line = line.as_ref();
|
||||
if line == "$ cd /" {
|
||||
self.curr_node = self.tree.root().id();
|
||||
self.change_director_root()
|
||||
} else if line == "$ cd .." {
|
||||
let node = self.curr_node();
|
||||
self.curr_node = node.parent().unwrap().id();
|
||||
self.change_directory_up()
|
||||
} 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();
|
||||
self.change_directory_to(target)
|
||||
} 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,
|
||||
});
|
||||
// Just ignore
|
||||
} else if line.starts_with("dir ") {
|
||||
// Nothing to do
|
||||
} else {
|
||||
panic!("What? {:?}", line);
|
||||
let (size, _label) = line.split_once(' ').expect("A dir list entry");
|
||||
self.push_file(size.parse().expect("A number for dir size"))
|
||||
}
|
||||
}
|
||||
|
||||
fn curr_node(&self) -> NodeRef {
|
||||
self.tree.get(self.curr_node).unwrap()
|
||||
fn change_director_root(&mut self) {
|
||||
while self.pwd.as_os_str() != "/" {
|
||||
self.change_directory_up()
|
||||
}
|
||||
}
|
||||
|
||||
fn curr_node_mut(&mut self) -> NodeMut {
|
||||
self.tree.get_mut(self.curr_node).unwrap()
|
||||
fn change_directory_up(&mut self) {
|
||||
let this_dir_size = self.sums.pop().expect("At least two elements here");
|
||||
*self.sums.last_mut().expect("At least one element here") += this_dir_size;
|
||||
self.pwd.pop();
|
||||
self.ext.change_directory_up(this_dir_size)
|
||||
}
|
||||
|
||||
fn finish(mut self) -> Tree {
|
||||
let node_id = self.tree.root().id();
|
||||
fill_size(&mut self.tree, node_id);
|
||||
self.tree
|
||||
fn change_directory_to(&mut self, target: &str) {
|
||||
self.pwd.push(target);
|
||||
self.sums.push(0);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
fn push_file(&mut self, size: usize) {
|
||||
*self.sums.last_mut().expect("At least one element here") += size;
|
||||
}
|
||||
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
|
||||
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()
|
||||
.collect::<Collector<PartOne>>()
|
||||
.ext
|
||||
.small_dirs_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
|
||||
let col = 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();
|
||||
.collect::<Collector<PartTwo>>();
|
||||
let root_size = col.sums.first().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")
|
||||
col.ext
|
||||
.smallest_relevant_dirs
|
||||
.into_iter_sorted()
|
||||
.find(|&Reverse(size)| size >= missing)
|
||||
// There is at least the root dir
|
||||
.unwrap()
|
||||
.0
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -178,6 +126,47 @@ fn main() {
|
|||
println!("{}", solution);
|
||||
}
|
||||
|
||||
impl<S, Ext> FromIterator<S> for Collector<Ext>
|
||||
where
|
||||
S: AsRef<str>,
|
||||
Ext: CollectorExt,
|
||||
{
|
||||
fn from_iter<T: IntoIterator<Item = S>>(iter: T) -> Self {
|
||||
let mut col = iter.into_iter().fold(Self::default(), |mut acc, line| {
|
||||
let line = line.as_ref();
|
||||
acc.push_line(line);
|
||||
acc
|
||||
});
|
||||
col.change_director_root();
|
||||
col
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ext: CollectorExt> Default for Collector<Ext> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
ext: Ext::default(),
|
||||
pwd: PathBuf::from("/"),
|
||||
sums: vec![0],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CollectorExt for PartOne {
|
||||
fn change_directory_up(&mut self, dir_size: usize) {
|
||||
const SMALL_DIR_MAX_SIZE: usize = 100000;
|
||||
if dir_size < SMALL_DIR_MAX_SIZE {
|
||||
self.small_dirs_sum += dir_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CollectorExt for PartTwo {
|
||||
fn change_directory_up(&mut self, dir_size: usize) {
|
||||
self.smallest_relevant_dirs.push(Reverse(dir_size))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::io::Cursor;
|
||||
|
|
Loading…
Reference in a new issue