clean up 2022/07

This commit is contained in:
kageru 2022-12-07 11:42:32 +01:00
parent 5c8e79c543
commit d2c569209e

View File

@ -1,6 +1,5 @@
#![feature(test)] #![feature(test, if_let_guard, iter_collect_into)]
extern crate test; extern crate test;
use std::ops::{Index, IndexMut};
use aoc2022::{boilerplate, common::*}; use aoc2022::{boilerplate, common::*};
@ -11,26 +10,15 @@ enum Node<'a> {
Dir(&'a str, Vec<Box<Node<'a>>>, usize), Dir(&'a str, Vec<Box<Node<'a>>>, usize),
} }
impl<'a> IndexMut<&str> for Node<'a> { impl<'a> Node<'a> {
fn index_mut(&mut self, index: &str) -> &mut Node<'a> { /// Implementing this rather than IndexMut because that requires a mostly redundant
/// implementation of Index which is more boilerplate.
fn subdir_mut(&mut self, dir: &str) -> &mut Self {
match self { match self {
Self::Dir(_, contents, _) => { Self::Dir(_, contents, _) => {
contents.iter_mut().find(|d| matches!(***d, Self::Dir(name, _, _) if name == index)).expect("File not found") contents.iter_mut().find(|d| matches!(***d, Self::Dir(name, _, _) if name == dir)).expect("File not found")
} }
Self::File(name, _) => panic!("Can’t index into a file ({name})"), Self::File(name, _) => panic!("Can't index into a file ({name})"),
}
}
}
impl<'a> Index<&str> for Node<'a> {
type Output = Self;
fn index(&self, index: &str) -> &Self::Output {
match self {
Self::Dir(_, contents, _) => {
contents.iter().find(|&d| matches!(**d, Self::Dir(name, _, _) if name == index)).expect("File not found")
}
Self::File(name, _) => panic!("Can’t index into a file ({name})"),
} }
} }
} }
@ -41,40 +29,30 @@ fn parse_input(raw: &str) -> Node<'_> {
for cmd in raw.trim_start_matches("$ cd /\n$ ").split("$ ") { for cmd in raw.trim_start_matches("$ cd /\n$ ").split("$ ") {
let mut lines = cmd.lines(); let mut lines = cmd.lines();
match lines.next().and_then(|s| s.split_once(' ')) { match lines.next().and_then(|s| s.split_once(' ')) {
Some(("cd", "..")) => { Some(("cd", "..")) => drop(pwd.pop()),
pwd.pop();
}
Some(("cd", dir)) => pwd.push(dir), Some(("cd", dir)) => pwd.push(dir),
// ls // ls
_ => { _ if let Node::Dir(_, contents, _) = pwd.iter().fold(&mut fs, |cd, p| cd.subdir_mut(p)) => {
let mut cd = &mut fs; lines
for p in pwd.iter() { .filter_map(|l| l.split_once(' '))
cd = &mut cd[p]; .map(|line| match line {
} ("dir", d) => Box::new(Node::Dir(d, Vec::new(), 0)),
match cd { (size, name) => Box::new(Node::File(name, size.parse().unwrap()))
Node::Dir(_, contents, _) => { })
for line in lines { .collect_into(contents);
match line.split_once(' ') {
Some(("dir", d)) => contents.push(Box::new(Node::Dir(d, Vec::new(), 0))),
Some((size, name)) => contents.push(Box::new(Node::File(name, size.parse().unwrap()))),
_ => unreachable!("Invalid directory contents: {line}"),
}
}
}
Node::File(_, _) => unreachable!("Can’t `ls` file contents"),
}
} }
_ => unreachable!()
}; };
} }
compute_dir_size(&mut fs); compute_dir_sizes(&mut fs);
fs fs
} }
fn compute_dir_size(node: &mut Node<'_>) -> usize { fn compute_dir_sizes(node: &mut Node<'_>) -> usize {
match node { match node {
Node::File(_, s) => *s, Node::File(_, s) => *s,
Node::Dir(_, c, size) => { Node::Dir(_, c, size) => {
*size = c.iter_mut().map(|d| compute_dir_size(d)).sum(); *size = c.iter_mut().map(|d| compute_dir_sizes(d)).sum();
*size *size
} }
} }
@ -131,7 +109,7 @@ $ ls
part2: { TEST_INPUT => 24933642 }, part2: { TEST_INPUT => 24933642 },
}, },
bench1 == 1667443, bench1 == 1667443,
bench2 == 0, bench2 == 8998590,
bench_parse: node_name => "/", bench_parse: node_name => "/",
} }