aoc/src/aoc2022/day07/mod.rs
2022-12-08 13:48:00 +01:00

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) = &current_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(&current_dir),
};
if let NodeType::Dir(nodes) = &current_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(&current_dir),
};
if let NodeType::Dir(nodes) = &current_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()
}