1
0

Day 7 part 2 implemented with trees

This commit is contained in:
Ishan Jain 2022-12-07 21:08:47 +05:30
parent 4073f69c84
commit ff8d6098a3
Signed by: ishan
GPG Key ID: 0506DB2A1CC75C27

View File

@ -1,4 +1,6 @@
#![feature(test)] #![feature(test)]
use std::collections::HashMap;
extern crate test; extern crate test;
const INPUTS: [&str; 2] = [ const INPUTS: [&str; 2] = [
@ -12,6 +14,19 @@ fn parse(input: &'static str) -> impl Iterator<Item = &'static str> {
input input
} }
#[derive(Debug)]
enum Node {
File(u32),
Directory(Directory),
}
#[derive(Debug)]
struct Directory {
children: HashMap<String, Node>,
parent: *mut Node,
size: u32,
}
fn main() { fn main() {
for input in INPUTS.iter() { for input in INPUTS.iter() {
let output = parse(input); let output = parse(input);
@ -22,56 +37,111 @@ fn main() {
} }
fn solution(input: impl Iterator<Item = &'static str>) -> u32 { fn solution(input: impl Iterator<Item = &'static str>) -> u32 {
let mut out = Vec::with_capacity(100); let mut tree = Node::Directory(Directory {
let mut stack = Vec::with_capacity(100); children: HashMap::new(),
parent: std::ptr::null_mut(),
size: 0,
});
let mut current_folder_size = 0; let mut current = &mut tree;
for line in input { for line in input {
match &line[..4] { match &line[..4] {
"$ ls" | "dir " => continue, "$ ls" => continue,
"dir " => {
let dir = &line[4..];
let cptr = current as *mut Node;
let Node::Directory(Directory { children, ..}) = current else { unreachable!()};
children.insert(
dir.to_string(),
Node::Directory(Directory {
children: HashMap::new(),
parent: cptr,
size: 0,
}),
);
}
"$ cd" => match &line[5..6] { "$ cd" => match &line[5..6] {
// we are supposed to match on .. but this is fine // we are supposed to match on .. but this is fine
"." => { "." => {
let v = stack.pop().unwrap(); let Node::Directory(Directory { parent , .. }) = *current else {
out.push(current_folder_size); unreachable!("current is not a directory");
current_folder_size += v; };
current = unsafe { &mut *parent };
} }
"/" => continue, "/" => current = &mut tree,
_ => { _ => {
stack.push(current_folder_size); let dir = &line[5..];
current_folder_size = 0; let Node::Directory(Directory { children, ..}) = current else {
unreachable!("current is not a directory");
};
current = children.get_mut(dir).unwrap();
} }
}, },
_ => { _ => {
let size = line let (size, name) = line.split_once(' ').unwrap();
let fsize = size
.bytes() .bytes()
.take_while(|&c| c != b' ') .take_while(|&c| c != b' ')
.fold(0u32, |a, x| a * 10 + (x - b'0') as u32); .fold(0u32, |a, x| a * 10 + (x - b'0') as u32);
current_folder_size += size;
if let Node::Directory(v) = current {
v.children
.entry(name.to_string())
.or_insert(Node::File(fsize));
}
} }
} }
} }
while let Some(v) = stack.pop() { compute_dir_size(&mut tree);
out.push(current_folder_size);
current_folder_size += v; part1(&tree)
}
fn part1(node: &Node) -> u32 {
match node {
&Node::File(_) => 0,
Node::Directory(dir) => {
let mut sum = 0;
if dir.size <= 100000 {
sum += dir.size;
} }
out.push(current_folder_size); for v in dir.children.values() {
sum += part1(v);
}
let available_space = 70000000; sum
let required_space = 30000000; }
let used_space = *out.last().unwrap(); }
}
out.into_iter() fn compute_dir_size(node: &mut Node) -> u32 {
.filter(|&c| c >= (required_space + used_space - available_space)) match node {
.min() &mut Node::File(v) => v,
.unwrap()
Node::Directory(dir) => {
let mut sum = 0;
for v in dir.children.values_mut() {
sum += compute_dir_size(v);
}
dir.size = sum;
sum
}
}
} }
#[bench] #[bench]