Solution for 2022/day07-part1

This commit is contained in:
Tobias Marschner 2024-02-11 16:50:05 +01:00
parent 02afcc631b
commit 2946a6a208

View File

@ -1,7 +1,7 @@
use std::{cell::RefCell, rc::Rc};
use std::{cell::RefCell, fmt, rc::Rc};
// Custom data structure
#[derive(Copy, Clone, Debug)]
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
enum NodeType {
File,
Directory,
@ -9,11 +9,27 @@ enum NodeType {
use NodeType::*;
// #[derive(Debug)]
struct Node {
node_type: NodeType,
name: String,
size: usize,
children: Vec<Rc<RefCell<Node>>>,
parent: Option<Rc<RefCell<Node>>>,
}
// Manual implementation of Debug for Node.
// Necessary in order to remove the "parent" field from the output.
// Otherwise the printer will print indefinitely.
impl fmt::Debug for Node {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Node")
.field("node_type", &self.node_type)
.field("name", &self.name)
.field("size", &self.size)
.field("children", &self.children)
.finish()
}
}
impl Node {
@ -23,6 +39,7 @@ impl Node {
name: String::from(name),
size,
children: Vec::new(),
parent: None,
}))
}
}
@ -40,13 +57,20 @@ fn main() {
let input = input.lines();
// --- TASK BEGIN ---
let mut result = 0;
// Set up our filesystem, starting with the root directory as the root node.
let root = Node::new(Directory, "/", 0);
// Also set up a
let current = root;
// Also keep track of all directories in the graph separately.
// This will help us actually determine the sum we're supposed to look for.
let mut dir_list: Vec<Rc<RefCell<Node>>> = Vec::new();
dir_list.push(root.clone());
// Also set up a pointer for the current directory.
let mut cd = root.clone();
// Keep track whether we're currently reading directories.
let mut ls_mode = false;
// Read line by line
for line in input {
@ -55,11 +79,111 @@ fn main() {
// First of all, differentiate between command and list item.
if line[0] == "$" {
match line[1] {
"cd" => {
// Changing directory.
ls_mode = false;
match line[2] {
"/" => {
// If the target is "/" switch back to the root directory.
cd = root.clone();
}
".." => {
// Switch to parent directory.
// First, we need to borrow the actual Node of the current directory.
let cd_node = cd.borrow();
// Grab an Rc to the parent...
let pd = cd_node.parent.clone().unwrap();
drop(cd_node);
// ...and assign it to cd.
cd = pd;
}
dir => {
// In the standard case, look for the child-node with the correct name.
// Get from the Rc<RefCell<Node>> to the actual Node.
let cd_node = cd.borrow();
// From there, find the child directory with the matching name.
let target_dir = cd_node
.children
.iter()
.find(|x| x.borrow().name == dir)
.unwrap()
.clone();
// Drop the Ref<_, Node> to ensure we drop the borrow on cd.
drop(cd_node);
// Now assign the new "current directory".
cd = target_dir;
}
}
}
"ls" => {
ls_mode = true;
}
_ => (),
}
} else {
println!("item");
// Looks like we're in list mode... right?
assert!(ls_mode);
// Assume it is a directory.
let mut node_type = Directory;
let mut size: usize = 0;
let name = line[1];
// If it is a file, update the size and type accordingly.
if line[0] != "dir" {
node_type = File;
size = line[0].parse::<usize>().unwrap();
}
// Now create the node for this file / directory.
let node = Node::new(node_type, name, size);
// Update the children of the current directory.
cd.borrow_mut().children.push(node.clone());
// And ensure the new node points back to the current directory.
node.borrow_mut().parent = Some(cd.clone());
// Also add any new directories to the directory list.
if node_type == Directory {
dir_list.push(node.clone());
}
}
}
println!("Result: {}", result);
// All files and directories have been parsed into the data structure.
// However, the size on all directories is currently 0.
// Determine the size of all directories recursively using DFS.
calc_node_size(root.clone());
// Finally, actually perform what the task requested.
let mut total: usize = 0;
for dir in &dir_list {
let size = dir.borrow().size;
if size <= 100000 {
total += size;
}
}
println!("Result: {}", total);
}
// Perform a depth-first-search on the tree in order to annotate the directory sizes.
// This method uses recursion to visit the entire tree.
fn calc_node_size(node: Rc<RefCell<Node>>) -> usize {
let mut inner_node = node.borrow_mut();
// If this node is a file, there's no recursion to be done.
// Simply return the size of the file.
if inner_node.node_type == File {
inner_node.size
} else {
let mut size: usize = 0;
// Iterate through all children and ...
for child in &inner_node.children {
// ... accumulate the size of all nodes recursively.
size += calc_node_size(child.clone());
}
// One more thing: Update the size of this directory before returning.
inner_node.size = size;
size
}
}