169 lines
4.7 KiB
Rust
169 lines
4.7 KiB
Rust
use std::{
|
|
cell::RefCell,
|
|
rc::{Rc, Weak},
|
|
};
|
|
|
|
#[derive(Debug)]
|
|
enum NodeType {
|
|
File(usize),
|
|
Dir(RefCell<Vec<Rc<Node>>>),
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
struct Node {
|
|
name: String,
|
|
typ: NodeType,
|
|
parent: Weak<Node>,
|
|
}
|
|
|
|
impl Node {
|
|
fn get_size(&self) -> usize {
|
|
let mut size = 0;
|
|
|
|
match &self.typ {
|
|
NodeType::File(filesize) => size = *filesize,
|
|
NodeType::Dir(dir_nodes) => {
|
|
for node in dir_nodes.borrow().iter() {
|
|
size += node.get_size()
|
|
}
|
|
}
|
|
}
|
|
|
|
size
|
|
}
|
|
}
|
|
|
|
fn parse_input(input: &str) -> Rc<Node> {
|
|
let root_node: Rc<Node> = Rc::new(Node {
|
|
name: String::from("/"),
|
|
typ: NodeType::Dir(RefCell::new(Vec::new())),
|
|
parent: Weak::new(),
|
|
});
|
|
|
|
let mut current_dir: Rc<Node> = root_node.clone();
|
|
|
|
for line in input.lines() {
|
|
if line.is_empty() {
|
|
continue;
|
|
}
|
|
|
|
let mut split = line.split_whitespace();
|
|
let first = split.next().unwrap();
|
|
let second = split.next().unwrap();
|
|
|
|
match (first, second) {
|
|
("$", "cd") => {
|
|
let next = split.next().unwrap();
|
|
if next != "/" {
|
|
match next {
|
|
".." => {
|
|
let bla = current_dir.parent.upgrade().unwrap();
|
|
current_dir = bla;
|
|
}
|
|
dir => {
|
|
let mut new_dir = current_dir.clone();
|
|
if let NodeType::Dir(nodes) = ¤t_dir.typ {
|
|
new_dir = nodes
|
|
.borrow()
|
|
.iter()
|
|
.find(|n| n.name == dir)
|
|
.unwrap()
|
|
.clone();
|
|
}
|
|
current_dir = new_dir;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
("$", "ls") => (),
|
|
(typ_size, name) => {
|
|
if let Ok(size) = typ_size.parse::<usize>() {
|
|
let new_node = Node {
|
|
name: name.to_string(),
|
|
typ: NodeType::File(size),
|
|
parent: Rc::downgrade(¤t_dir),
|
|
};
|
|
|
|
if let NodeType::Dir(nodes) = ¤t_dir.typ {
|
|
nodes.borrow_mut().push(Rc::new(new_node));
|
|
}
|
|
} else {
|
|
let new_node = Node {
|
|
name: name.to_string(),
|
|
typ: NodeType::Dir(RefCell::new(Vec::new())),
|
|
parent: Rc::downgrade(¤t_dir),
|
|
};
|
|
|
|
if let NodeType::Dir(nodes) = ¤t_dir.typ {
|
|
nodes.borrow_mut().push(Rc::new(new_node));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
root_node
|
|
}
|
|
|
|
fn find(node: Rc<Node>, max_size: usize) -> usize {
|
|
let mut total_size = 0;
|
|
|
|
if let NodeType::Dir(nodes) = &node.typ {
|
|
for node in nodes.borrow().iter() {
|
|
if let NodeType::Dir(_) = &node.typ {
|
|
let size = node.get_size();
|
|
if size < max_size {
|
|
total_size += size;
|
|
}
|
|
total_size += find(node.clone(), max_size);
|
|
}
|
|
}
|
|
}
|
|
|
|
total_size
|
|
}
|
|
|
|
fn find_best_fit(node: Rc<Node>, size: usize) -> usize {
|
|
let mut actual_size = usize::MAX;
|
|
|
|
if let NodeType::Dir(nodes) = &node.typ {
|
|
for node in nodes.borrow().iter() {
|
|
if let NodeType::Dir(_) = &node.typ {
|
|
let node_size = node.get_size();
|
|
if node_size >= size {
|
|
if actual_size > node_size {
|
|
actual_size = node_size;
|
|
}
|
|
let deeper = find_best_fit(node.clone(), size);
|
|
|
|
if actual_size > deeper {
|
|
actual_size = deeper;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
actual_size
|
|
}
|
|
|
|
pub fn task_one(input: &str) -> String {
|
|
let root = parse_input(&input);
|
|
|
|
// if let NodeType::Dir(nodes) = &root.typ {
|
|
// println!("{:?}", nodes.borrow())
|
|
// }
|
|
|
|
find(root, 100_000).to_string()
|
|
}
|
|
|
|
pub fn task_two(input: &str) -> String {
|
|
const TOTAL_SPACE: usize = 70_000_000;
|
|
const REQUIRED_FREE_SPACE: usize = 30_000_000;
|
|
|
|
let root = parse_input(&input);
|
|
let required_space = REQUIRED_FREE_SPACE - (TOTAL_SPACE - root.get_size());
|
|
|
|
find_best_fit(root, required_space).to_string()
|
|
}
|