2022 rust day 7 refactor

This commit is contained in:
Maciej Jur 2022-12-07 19:08:59 +01:00
parent 1cd2721b61
commit 276b515e6d

View file

@ -4,7 +4,7 @@ use crate::utils;
pub fn run() -> () { pub fn run() -> () {
let data = parse_data(utils::read_lines(utils::Source::Day(7))); let data = parse_data(&utils::read_lines(utils::Source::Day(7)));
println!("Day 7"); println!("Day 7");
println!("Part 1: {}", solve1(&data)); println!("Part 1: {}", solve1(&data));
@ -23,6 +23,7 @@ struct FileNode {
size: i32, size: i32,
} }
#[derive(Default)]
struct Node<'data> { struct Node<'data> {
name: &'data str, name: &'data str,
// Backref pointer // Backref pointer
@ -31,14 +32,8 @@ struct Node<'data> {
subdirs: Vec<Box<Node<'data>>>, subdirs: Vec<Box<Node<'data>>>,
} }
impl<'data> Node<'data> {
fn new(name: &'data str, parent: Option<*mut Node<'data>>) -> Node<'data> {
Node { name, parent, files: vec![], subdirs: vec![] }
}
}
fn cli_to_tree(data: &[CliEntry]) -> Box<Node> { fn cli_to_tree(data: &[CliEntry]) -> Box<Node> {
let mut root = Box::new(Node::new("/", None)); let mut root = Box::new(Node { name: "/", ..Default::default() });
let mut current: &mut Node = root.as_mut(); let mut current: &mut Node = root.as_mut();
for command in data { for command in data {
@ -59,7 +54,7 @@ fn cli_to_tree(data: &[CliEntry]) -> Box<Node> {
CliEntry::Ls => {}, CliEntry::Ls => {},
CliEntry::Dir(name) => { CliEntry::Dir(name) => {
let current_ptr = current as *mut Node; let current_ptr = current as *mut Node;
current.subdirs.push(Box::new(Node::new(name, Some(current_ptr)))); current.subdirs.push(Box::new(Node { name, parent: Some(current_ptr), ..Default::default() }));
}, },
CliEntry::File(_, size) => { CliEntry::File(_, size) => {
current.files.push(FileNode { size: *size }) current.files.push(FileNode { size: *size })
@ -69,23 +64,24 @@ fn cli_to_tree(data: &[CliEntry]) -> Box<Node> {
root root
} }
fn find_sizes(root: &Box<Node>) -> (i32, BinaryHeap<i32>) { fn find_sizes(node: &Box<Node>, heap: &mut BinaryHeap<i32>) -> i32 {
let mut acc: i32 = root.files.iter().map(|f| f.size).sum(); let mut acc: i32 = 0;
let mut sizes: BinaryHeap<i32> = BinaryHeap::new(); for file in &node.files {
root.subdirs.iter().for_each(|subdir| { acc += file.size;
let (sub_size, sub_sizes) = find_sizes(subdir); }
sizes.extend(sub_sizes.iter()); for subdir in &node.subdirs {
acc += sub_size; acc += find_sizes(subdir, heap);
}); }
sizes.push(acc); heap.push(acc);
(acc, sizes) acc
} }
fn solve1(data: &[CliEntry]) -> i32 { fn solve1(data: &[CliEntry]) -> i32 {
let tree = cli_to_tree(&data[1..]); let tree = cli_to_tree(&data[1..]);
let (_, sizes) = find_sizes(&tree); let mut heap: BinaryHeap<i32> = BinaryHeap::new();
find_sizes(&tree, &mut heap);
sizes.into_iter() heap.into_iter()
.filter_map(|size| size .filter_map(|size| size
.le(&100000) .le(&100000)
.then_some(size) .then_some(size)
@ -97,10 +93,11 @@ fn solve2(data: &[CliEntry]) -> i32 {
static DISK_SPACE: i32 = 70000000; static DISK_SPACE: i32 = 70000000;
static REQUIRED: i32 = 30000000; static REQUIRED: i32 = 30000000;
let tree = cli_to_tree(&data[1..]); let tree = cli_to_tree(&data[1..]);
let (size, sizes) = find_sizes(&tree); let mut heap: BinaryHeap<i32> = BinaryHeap::new();
let size = find_sizes(&tree, &mut heap);
let threshold = REQUIRED - (DISK_SPACE - size); let threshold = REQUIRED - (DISK_SPACE - size);
sizes.into_sorted_vec() heap.into_sorted_vec()
.into_iter() .into_iter()
.filter(|&x| x > threshold) .filter(|&x| x > threshold)
.next() .next()
@ -108,9 +105,10 @@ fn solve2(data: &[CliEntry]) -> i32 {
} }
fn parse_data(data: Vec<String>) -> Vec<CliEntry> { fn parse_data<T: AsRef<str>>(data: &[T]) -> Vec<CliEntry> {
data.into_iter() data.into_iter()
.map(|s| { .map(|str_ref| {
let s = str_ref.as_ref();
let mut parts = s.split_whitespace().into_iter(); let mut parts = s.split_whitespace().into_iter();
if s.starts_with('$') { if s.starts_with('$') {
match parts.nth(1).unwrap() { match parts.nth(1).unwrap() {
@ -134,31 +132,28 @@ fn parse_data(data: Vec<String>) -> Vec<CliEntry> {
mod tests { mod tests {
use super::*; use super::*;
fn data() -> Vec<String> { static DATA: &[&str; 23] = &[
vec![ "$ cd /",
"$ cd /", "$ ls", "dir a", "14848514 b.txt", "8504156 c.dat", "dir d",
"$ ls", "dir a", "14848514 b.txt", "8504156 c.dat", "dir d", "$ cd a",
"$ cd a", "$ ls", "dir e", "29116 f", "2557 g", "62596 h.lst",
"$ ls", "dir e", "29116 f", "2557 g", "62596 h.lst", "$ cd e",
"$ cd e", "$ ls", "584 i",
"$ ls", "584 i", "$ cd ..",
"$ cd ..", "$ cd ..",
"$ cd ..", "$ cd d",
"$ cd d", "$ ls", "4060174 j", "8033020 d.log", "5626152 d.ext", "7214296 k",
"$ ls", "4060174 j", "8033020 d.log", "5626152 d.ext", "7214296 k", ];
]
.into_iter().map(String::from).collect()
}
#[test] #[test]
fn part1() { fn part1() {
let data = parse_data(data()); let data = parse_data(DATA);
assert_eq!(95437, solve1(&data)); assert_eq!(95437, solve1(&data));
} }
#[test] #[test]
fn part2() { fn part2() {
let data = parse_data(data()); let data = parse_data(DATA);
assert_eq!(24933642, solve2(&data)); assert_eq!(24933642, solve2(&data));
} }
} }