Skip to content
Snippets Groups Projects
Commit f36effb9 authored by Falk Rehse's avatar Falk Rehse
Browse files

Day 7-2

parent 4d0c1190
No related branches found
No related tags found
1 merge request!1Day 7
use self::Command::{ChangeDir, List};
use crate::day_7_2::node::Node;
#[derive(Debug)]
pub enum Command {
ChangeDir { path: String },
List { files: Vec<Node> },
}
impl Command {
pub fn from_str(input: &str) -> Command {
let mut data = input.split("\n");
let command = data.next().expect("Expected a command!");
let cmd = command.split(' ').next().expect("Expected a command!");
match cmd {
"cd" => {
let path = command.split(' ').nth(1).expect("Expected a path!");
ChangeDir {
path: path.to_string(),
}
}
"ls" => {
let files = data.filter_map(|file| Node::from_str(file)).collect();
List { files }
}
_ => panic!("Unexpected command!"),
}
}
}
use std::cell::{RefCell, RefMut};
use std::rc::Rc;
use crate::day_7_2::command::Command;
use crate::day_7_2::node::Node::File;
#[derive(Debug, Clone)]
pub enum FileTree {
File {
name: String,
parent: Option<Rc<RefCell<FileTree>>>,
size: u32,
},
Directory {
name: String,
parent: Option<Rc<RefCell<FileTree>>>,
files: Vec<Rc<RefCell<FileTree>>>,
},
}
impl FileTree {
pub fn new() -> FileTree {
Self::Directory {
name: "".to_string(),
parent: None,
files: Vec::new(),
}
}
pub fn from_commands(commands: &Vec<Command>) -> FileTree {
let result_tree = Rc::new(RefCell::new(Self::new()));
let mut tree = Rc::clone(&result_tree);
for command in commands {
match command {
Command::ChangeDir { path } => {
tree = Self::change_path(tree, &path);
}
Command::List { files } => {
for file in files {
if let File { name, size } = file {
let file_tree = Rc::clone(&tree);
tree.borrow_mut().add_file(file_tree, name, size);
}
}
}
}
}
let tree = result_tree.borrow();
tree.clone()
}
fn change_path(tree: Rc<RefCell<FileTree>>, path: &str) -> Rc<RefCell<FileTree>> {
if path == "/" {
tree
} else if path == ".." {
if let Some(tree) = tree.borrow_mut().get_parent() {
Rc::clone(tree)
} else {
panic!("Expected parent directory!");
}
} else {
Self::create_directory(tree, path)
}
}
fn create_directory(tree: Rc<RefCell<FileTree>>, path: &str) -> Rc<RefCell<FileTree>> {
let file_tree = tree.as_ref().borrow_mut();
let mut files = RefMut::map(file_tree, |t| {
if let Self::Directory { files, .. } = t {
files
} else {
panic!("Expected a directory!");
}
});
let directory = Self::Directory {
name: path.to_string(),
parent: Some(Rc::clone(&tree)),
files: Vec::new(),
};
let directory = Rc::new(RefCell::new(directory));
files.push(Rc::clone(&directory));
directory
}
fn add_file(&mut self, tree: Rc<RefCell<FileTree>>, name: &str, size: &u32) {
if let Self::Directory { files, .. } = self {
files.push(Rc::new(RefCell::new(Self::File {
name: name.to_string(),
parent: Some(tree),
size: size.clone(),
})))
}
}
fn get_parent(&mut self) -> &mut Option<Rc<RefCell<FileTree>>> {
match self {
Self::Directory { parent, .. } => parent,
Self::File { parent, .. } => parent,
}
}
}
mod command;
mod file_tree;
mod node;
use std::{cell::RefCell, rc::Rc};
use command::Command;
use file_tree::FileTree;
const FILESYSTEM_SIZE: u32 = 70_000_000;
const FREE_SPACE_REQUIRED: u32 = 30_000_000;
pub fn solve_from_str(input: &str) -> u32 {
let mut commands = input.split("$ ");
commands.next();
let commands = commands.map(|command| Command::from_str(command)).collect();
let file_tree = FileTree::from_commands(&commands);
solve(file_tree)
}
pub fn solve(file_tree: FileTree) -> u32 {
let file_tree = Rc::new(RefCell::new(file_tree));
let used_space = get_file_tree_size(&file_tree);
let unused_space = FILESYSTEM_SIZE - used_space;
let size_to_free = FREE_SPACE_REQUIRED - unused_space;
let mut candidates = Vec::new();
traverse_file_tree(&file_tree, &mut candidates, size_to_free);
candidates.sort_unstable();
*candidates.first().unwrap()
}
fn traverse_file_tree(file_tree: &Rc<RefCell<FileTree>>, candidates: &mut Vec<u32>, size_to_free: u32) {
let total_size = match &*file_tree.borrow() {
FileTree::Directory { files, .. } => {
for file in files {
traverse_file_tree(file, candidates, size_to_free);
}
get_file_tree_size(file_tree)
},
FileTree::File { .. } => { 0 }
};
if total_size >= size_to_free {
candidates.push(total_size);
}
}
fn get_file_tree_size(file_tree: &Rc<RefCell<FileTree>>) -> u32 {
match &*file_tree.borrow() {
FileTree::Directory { files, .. } => {
files.iter().map(|file| get_file_tree_size(file)).sum()
},
FileTree::File { size, .. } => {
*size
}
}
}
use self::Node::{Directory, File};
#[derive(Debug)]
pub enum Node {
File { name: String, size: u32 },
Directory { name: String },
}
impl Node {
pub fn from_str(input: &str) -> Option<Node> {
if input == "" {
return None;
}
if input.starts_with("dir") {
Some(Directory {
name: input
.split(' ')
.nth(1)
.expect("Expected directory name!")
.to_string(),
})
} else {
Some(File {
name: input
.split(' ')
.nth(1)
.expect("Expected file name!")
.to_string(),
size: input
.split(' ')
.nth(0)
.expect("Expected file size!")
.parse()
.expect("Expected file size to be a number!"),
})
}
}
}
......@@ -11,13 +11,14 @@ mod day_5_2;
mod day_6_1;
mod day_6_2;
mod day_7_1;
mod day_7_2;
use std::fs;
fn main() {
let input = fs::read_to_string("input").expect("Could not read input!");
let solution = day_7_1::solve_from_str(input.as_str());
let solution = day_7_2::solve_from_str(input.as_str());
println!("Solution: {}", solution);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment