switched to workspaces.
This should let me make a cross-day library.
This commit is contained in:
parent
1469c3a32b
commit
242989bb95
57 changed files with 156 additions and 89 deletions
11
days/day07/Cargo.toml
Normal file
11
days/day07/Cargo.toml
Normal file
|
@ -0,0 +1,11 @@
|
|||
[package]
|
||||
name = "day07"
|
||||
authors.workspace = true
|
||||
description.workspace = true
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[dependencies]
|
||||
once_cell.workspace = true
|
||||
regex.workspace = true
|
||||
thiserror.workspace = true
|
305
days/day07/src/file_tree.rs
Normal file
305
days/day07/src/file_tree.rs
Normal file
|
@ -0,0 +1,305 @@
|
|||
use std::{
|
||||
cell::RefCell,
|
||||
fmt::Display,
|
||||
ops::Deref,
|
||||
rc::{Rc, Weak},
|
||||
};
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum FileTreeError {
|
||||
#[error("Directory operation on file")]
|
||||
IsFile,
|
||||
#[error("File operation on directory")]
|
||||
IsDir,
|
||||
#[error("File not found")]
|
||||
FileNotFound,
|
||||
#[error("File already exists")]
|
||||
FileAlreadyExists,
|
||||
}
|
||||
|
||||
type WeakNodeRef = Weak<RefCell<Node>>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct NodeRef(pub Rc<RefCell<Node>>);
|
||||
|
||||
impl Deref for NodeRef {
|
||||
type Target = Rc<RefCell<Node>>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Rc<RefCell<Node>>> for NodeRef {
|
||||
fn from(value: Rc<RefCell<Node>>) -> Self {
|
||||
NodeRef(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<NodeRef> for Rc<RefCell<Node>> {
|
||||
fn from(value: NodeRef) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
impl NodeRef {
|
||||
pub fn add_node(&mut self, mut node: Node) -> Result<NodeRef, FileTreeError> {
|
||||
node.set_parent(self);
|
||||
self.borrow_mut().add_children(node)
|
||||
}
|
||||
pub fn new_dir(name: String) -> NodeRef {
|
||||
NodeRef(Rc::new(RefCell::new(Node::new_dir(name))))
|
||||
}
|
||||
pub fn add_file(&mut self, name: String, size: usize) -> Result<NodeRef, FileTreeError> {
|
||||
self.add_node(Node::new_file(name, size))
|
||||
}
|
||||
pub fn add_dir(&mut self, name: String) -> Result<NodeRef, FileTreeError> {
|
||||
self.add_node(Node::new_dir(name))
|
||||
}
|
||||
pub fn get_all_dirs(&self) -> Vec<NodeRef> {
|
||||
let mut ret = Vec::new();
|
||||
match &self.borrow().contents {
|
||||
Contents::Size(_) => {}
|
||||
Contents::Children(c) => {
|
||||
ret.push(NodeRef(Rc::clone(self)));
|
||||
for node in c {
|
||||
ret.append(&mut node.get_all_dirs())
|
||||
}
|
||||
}
|
||||
};
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Node {
|
||||
pub name: String,
|
||||
parent: Option<WeakNodeRef>,
|
||||
contents: Contents,
|
||||
}
|
||||
|
||||
impl Node {
|
||||
pub fn new_dir(name: String) -> Node {
|
||||
Node {
|
||||
name,
|
||||
parent: None,
|
||||
contents: Contents::Children(Vec::new()),
|
||||
}
|
||||
}
|
||||
pub fn new_file(name: String, size: usize) -> Node {
|
||||
Node {
|
||||
name,
|
||||
parent: None,
|
||||
contents: Contents::Size(size),
|
||||
}
|
||||
}
|
||||
pub fn get_total_size(&self) -> usize {
|
||||
match &self.contents {
|
||||
Contents::Size(s) => *s,
|
||||
Contents::Children(c) => c.iter().map(|f| f.borrow().get_total_size()).sum(),
|
||||
}
|
||||
}
|
||||
fn set_parent(&mut self, newparent: &NodeRef) {
|
||||
self.parent = Some(Rc::downgrade(newparent));
|
||||
}
|
||||
// does not set the parent, needs to be done on the NodeRef. (this is why this func isnt pub).
|
||||
// takes onwership of the node to make sure its not owned by another tree.
|
||||
fn add_children(&mut self, node: Node) -> Result<NodeRef, FileTreeError> {
|
||||
match self.contents {
|
||||
Contents::Size(_) => Err(FileTreeError::IsFile),
|
||||
Contents::Children(ref mut c) => {
|
||||
for file in c.iter() {
|
||||
if file.borrow().name == node.name {
|
||||
return Err(FileTreeError::FileAlreadyExists);
|
||||
}
|
||||
}
|
||||
let rc = Rc::new(RefCell::new(node));
|
||||
c.push(NodeRef(Rc::clone(&rc)));
|
||||
Ok(NodeRef(Rc::clone(&rc)))
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn remove_child_by_name(&mut self, name: &str) -> Result<(), FileTreeError> {
|
||||
match self.contents {
|
||||
Contents::Size(_) => Err(FileTreeError::IsFile),
|
||||
Contents::Children(ref mut c) => {
|
||||
for (i, file) in c.iter().enumerate() {
|
||||
if file.borrow().name == name {
|
||||
c.remove(i);
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Err(FileTreeError::FileNotFound)
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn get_parent(&self) -> Option<NodeRef> {
|
||||
match &self.parent {
|
||||
Some(w) => Some(NodeRef(w.clone().upgrade()?)),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
pub fn get_size(&self) -> Result<usize, FileTreeError> {
|
||||
match self.contents {
|
||||
Contents::Size(s) => Ok(s),
|
||||
Contents::Children(_) => Err(FileTreeError::IsDir),
|
||||
}
|
||||
}
|
||||
pub fn set_size(&mut self, size: usize) -> Result<(), FileTreeError> {
|
||||
match self.contents {
|
||||
Contents::Size(ref mut s) => {
|
||||
*s = size;
|
||||
Ok(())
|
||||
}
|
||||
Contents::Children(_) => Err(FileTreeError::IsDir),
|
||||
}
|
||||
}
|
||||
pub fn get_children(&self) -> Result<impl Iterator<Item = NodeRef> + '_, FileTreeError> {
|
||||
match &self.contents {
|
||||
Contents::Size(_) => Err(FileTreeError::IsFile),
|
||||
Contents::Children(c) => Ok(c.iter().map(|n| NodeRef(Rc::clone(n)))),
|
||||
}
|
||||
}
|
||||
pub fn get_child_by_name(&self, name: &str) -> Result<NodeRef, FileTreeError> {
|
||||
match &self.contents {
|
||||
Contents::Size(_) => Err(FileTreeError::IsFile),
|
||||
Contents::Children(c) => {
|
||||
for file in c.iter() {
|
||||
if file.borrow().name == name {
|
||||
return Ok(NodeRef(Rc::clone(file)));
|
||||
}
|
||||
}
|
||||
Err(FileTreeError::FileNotFound)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Contents {
|
||||
Size(usize),
|
||||
Children(Vec<NodeRef>),
|
||||
}
|
||||
|
||||
impl Display for NodeRef {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.borrow())
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Node {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "- {} {}", self.name, self.contents)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Contents {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Contents::Size(s) => write!(f, "(file, size = {})", s),
|
||||
Contents::Children(c) => {
|
||||
writeln!(f, "(dir)").expect("I have no clue how this could fail");
|
||||
for node in c {
|
||||
//padding
|
||||
for line in format!("{}", node).lines() {
|
||||
writeln!(f, " {line}")?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_dir_construction() {
|
||||
let mut root = NodeRef::new_dir("/".to_string());
|
||||
let mut cursor = root.add_node(Node::new_dir("a".to_string())).unwrap();
|
||||
cursor = cursor.add_dir("e".to_string()).unwrap();
|
||||
cursor.add_file("i".to_string(), 584).unwrap();
|
||||
cursor = Rc::clone(cursor.deref()).borrow().get_parent().unwrap();
|
||||
cursor.add_file("f".to_string(), 29116).unwrap();
|
||||
cursor.add_file("g".to_string(), 2557).unwrap();
|
||||
cursor.add_file("h.lst".to_string(), 62596).unwrap();
|
||||
cursor = Rc::clone(cursor.deref()).borrow().get_parent().unwrap();
|
||||
cursor.add_file("b.txt".to_string(), 14848514).unwrap();
|
||||
cursor.add_file("c.dat".to_string(), 8504156).unwrap();
|
||||
cursor = cursor.add_dir("d".to_string()).unwrap();
|
||||
cursor.add_file("j".to_string(), 4060174).unwrap();
|
||||
cursor.add_file("d.log".to_string(), 8033020).unwrap();
|
||||
cursor.add_file("d.ext".to_string(), 5626152).unwrap();
|
||||
cursor.add_file("k".to_string(), 7214296).unwrap();
|
||||
assert_eq!(Rc::clone(root.deref()).borrow().get_total_size(), 48381165);
|
||||
println!("{}", root);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_size_calcs() {
|
||||
let mut root = NodeRef::new_dir("/".to_string());
|
||||
let mut dirs: Vec<NodeRef> = Vec::new();
|
||||
let mut cursor = root.add_dir("a".to_string()).unwrap();
|
||||
dirs.push(NodeRef(Rc::clone(&cursor)));
|
||||
cursor = cursor.add_dir("e".to_string()).unwrap();
|
||||
dirs.push(NodeRef(Rc::clone(&cursor)));
|
||||
cursor.add_file("i".to_string(), 584).unwrap();
|
||||
cursor = Rc::clone(cursor.deref()).borrow().get_parent().unwrap();
|
||||
cursor.add_file("f".to_string(), 29116).unwrap();
|
||||
cursor.add_file("g".to_string(), 2557).unwrap();
|
||||
cursor.add_file("h.lst".to_string(), 62596).unwrap();
|
||||
cursor = Rc::clone(cursor.deref()).borrow().get_parent().unwrap();
|
||||
cursor.add_file("b.txt".to_string(), 14848514).unwrap();
|
||||
cursor.add_file("c.dat".to_string(), 8504156).unwrap();
|
||||
cursor = cursor.add_node(Node::new_dir("d".to_string())).unwrap();
|
||||
dirs.push(NodeRef(Rc::clone(&cursor)));
|
||||
cursor.add_file("j".to_string(), 4060174).unwrap();
|
||||
cursor.add_file("d.log".to_string(), 8033020).unwrap();
|
||||
cursor.add_file("d.ext".to_string(), 5626152).unwrap();
|
||||
cursor.add_file("k".to_string(), 7214296).unwrap();
|
||||
assert_eq!(Rc::clone(root.deref()).borrow().get_total_size(), 48381165);
|
||||
assert_eq!(Rc::clone(dirs[0].deref()).borrow().get_total_size(), 94853);
|
||||
assert_eq!(Rc::clone(dirs[1].deref()).borrow().get_total_size(), 584);
|
||||
assert_eq!(
|
||||
Rc::clone(dirs[2].deref()).borrow().get_total_size(),
|
||||
24933642
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn test_get_all_dirs() {
|
||||
let mut root = NodeRef::new_dir("/".to_string());
|
||||
let mut cursor = root.add_dir("a".to_string()).unwrap();
|
||||
cursor = cursor.add_dir("e".to_string()).unwrap();
|
||||
cursor.add_file("i".to_string(), 584).unwrap();
|
||||
cursor = Rc::clone(cursor.deref()).borrow().get_parent().unwrap();
|
||||
cursor.add_file("f".to_string(), 29116).unwrap();
|
||||
cursor.add_file("g".to_string(), 2557).unwrap();
|
||||
cursor.add_file("h.lst".to_string(), 62596).unwrap();
|
||||
cursor = Rc::clone(cursor.deref()).borrow().get_parent().unwrap();
|
||||
cursor.add_file("b.txt".to_string(), 14848514).unwrap();
|
||||
cursor.add_file("c.dat".to_string(), 8504156).unwrap();
|
||||
cursor = cursor.add_node(Node::new_dir("d".to_string())).unwrap();
|
||||
cursor.add_file("j".to_string(), 4060174).unwrap();
|
||||
cursor.add_file("d.log".to_string(), 8033020).unwrap();
|
||||
cursor.add_file("d.ext".to_string(), 5626152).unwrap();
|
||||
cursor.add_file("k".to_string(), 7214296).unwrap();
|
||||
let dirs = root.get_all_dirs();
|
||||
let sizes: Vec<usize> = dirs.iter().map(|d| d.borrow().get_total_size()).collect();
|
||||
println!("{:?}", sizes);
|
||||
assert_eq!(Rc::clone(root.deref()).borrow().get_total_size(), 48381165);
|
||||
assert_eq!(
|
||||
Rc::clone(dirs[0].deref()).borrow().get_total_size(),
|
||||
48381165
|
||||
);
|
||||
assert_eq!(Rc::clone(dirs[1].deref()).borrow().get_total_size(), 94853);
|
||||
assert_eq!(Rc::clone(dirs[2].deref()).borrow().get_total_size(), 584);
|
||||
assert_eq!(
|
||||
Rc::clone(dirs[3].deref()).borrow().get_total_size(),
|
||||
24933642
|
||||
);
|
||||
}
|
||||
}
|
1030
days/day07/src/input.txt
Normal file
1030
days/day07/src/input.txt
Normal file
File diff suppressed because it is too large
Load diff
19
days/day07/src/main.rs
Normal file
19
days/day07/src/main.rs
Normal file
|
@ -0,0 +1,19 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use crate::file_tree::NodeRef;
|
||||
|
||||
mod part1;
|
||||
mod part2;
|
||||
mod parser;
|
||||
mod file_tree;
|
||||
|
||||
fn main() {
|
||||
let input = include_str!("./input.txt");
|
||||
let structured_input = parser::parse(input);
|
||||
|
||||
println!("Part One");
|
||||
println!("Result: {}", part1::part1(NodeRef(Rc::clone(&structured_input))));
|
||||
|
||||
println!("Part Two");
|
||||
println!("Result: {}", part2::part2(NodeRef(Rc::clone(&structured_input))));
|
||||
}
|
262
days/day07/src/parser.rs
Normal file
262
days/day07/src/parser.rs
Normal file
|
@ -0,0 +1,262 @@
|
|||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::file_tree::*;
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
|
||||
static IS_COMMAND_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"^\$").unwrap());
|
||||
static PARSE_CD_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"^\$ cd (\S*)$").unwrap());
|
||||
static PARSE_LS_ENTRY_REGEX: Lazy<Regex> =
|
||||
Lazy::new(|| Regex::new(r"^([[:alnum:]]*) (\S*)$").unwrap());
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum Command {
|
||||
CdRoot,
|
||||
CdUp,
|
||||
Cd(String),
|
||||
Ls(Vec<LsEntry>),
|
||||
}
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum LsEntry {
|
||||
Dir(String),
|
||||
File(ParseFile),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct ParseFile {
|
||||
size: usize,
|
||||
name: String,
|
||||
}
|
||||
|
||||
//parses a single line
|
||||
pub fn parse_to_commands(input: &str) -> Vec<Command> {
|
||||
let mut ret = Vec::new();
|
||||
let mut lines = input.lines().peekable();
|
||||
while lines.peek().is_some() {
|
||||
let line = lines.next().unwrap();
|
||||
if line == "$ ls" {
|
||||
ret.push(Command::Ls(parse_ls(&mut lines)));
|
||||
} else {
|
||||
let captures = PARSE_CD_REGEX
|
||||
.captures(line)
|
||||
.unwrap_or_else(|| panic!("invalid line {}", line));
|
||||
|
||||
ret.push(match &captures[1] {
|
||||
".." => Command::CdUp,
|
||||
"/" => Command::CdRoot,
|
||||
s => Command::Cd(s.to_string()),
|
||||
})
|
||||
}
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
fn parse_ls(lines: &mut std::iter::Peekable<std::str::Lines<'_>>) -> Vec<LsEntry> {
|
||||
let mut ret: Vec<LsEntry> = Vec::new();
|
||||
while lines.peek().is_some() {
|
||||
// if the next line is a command, then we are at the end of the ls listing.
|
||||
let line = lines.peek().expect("no next line");
|
||||
if IS_COMMAND_REGEX.is_match(line) {
|
||||
break;
|
||||
}
|
||||
let captures = PARSE_LS_ENTRY_REGEX
|
||||
.captures(line)
|
||||
.unwrap_or_else(|| panic!("invalid line {}", line));
|
||||
ret.push(match &captures[1] {
|
||||
"dir" => LsEntry::Dir(captures[2].to_string()),
|
||||
_ => LsEntry::File(ParseFile {
|
||||
size: str::parse(&captures[1]).unwrap_or_else(|_| panic!("invalid line {}", line)),
|
||||
name: captures[2].to_string(),
|
||||
}),
|
||||
});
|
||||
lines.next();
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
pub fn parse(input: &str) -> NodeRef {
|
||||
commands_to_tree(parse_to_commands(input))
|
||||
}
|
||||
|
||||
pub fn commands_to_tree(input: Vec<Command>) -> NodeRef {
|
||||
let root = NodeRef::new_dir("/".to_string());
|
||||
let mut cursor = NodeRef(Rc::clone(&root));
|
||||
for command in input {
|
||||
match command {
|
||||
Command::CdRoot => cursor = NodeRef(Rc::clone(&root)),
|
||||
Command::CdUp => cursor = Rc::clone(cursor.deref()).borrow().get_parent().unwrap(),
|
||||
Command::Cd(name) => cursor = cursor.add_dir(name).unwrap(),
|
||||
Command::Ls(ls) => {
|
||||
for entry in ls {
|
||||
match entry {
|
||||
LsEntry::Dir(_) => {
|
||||
//dirs dont exist until you cd into them.
|
||||
}
|
||||
LsEntry::File(f) => {
|
||||
cursor.add_file(f.name, f.size).unwrap();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
root
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_parse_to_commands() {
|
||||
let input = concat!(
|
||||
"$ cd /\n",
|
||||
"$ ls\n",
|
||||
"dir a\n",
|
||||
"14848514 b.txt\n",
|
||||
"8504156 c.dat\n",
|
||||
"dir d\n",
|
||||
"$ cd a\n",
|
||||
"$ ls\n",
|
||||
"dir e\n",
|
||||
"29116 f\n",
|
||||
"2557 g\n",
|
||||
"62596 h.lst\n",
|
||||
"$ cd e\n",
|
||||
"$ ls\n",
|
||||
"584 i\n",
|
||||
"$ cd ..\n",
|
||||
"$ cd ..\n",
|
||||
"$ cd d\n",
|
||||
"$ ls\n",
|
||||
"4060174 j\n",
|
||||
"8033020 d.log\n",
|
||||
"5626152 d.ext\n",
|
||||
"7214296 k"
|
||||
);
|
||||
assert_eq!(
|
||||
parse_to_commands(input),
|
||||
vec![
|
||||
Command::CdRoot,
|
||||
Command::Ls(vec![
|
||||
LsEntry::Dir(String::from("a")),
|
||||
LsEntry::File(ParseFile {
|
||||
size: 14848514,
|
||||
name: String::from("b.txt")
|
||||
}),
|
||||
LsEntry::File(ParseFile {
|
||||
size: 8504156,
|
||||
name: String::from("c.dat")
|
||||
}),
|
||||
LsEntry::Dir(String::from("d"))
|
||||
]),
|
||||
Command::Cd(String::from("a")),
|
||||
Command::Ls(vec![
|
||||
LsEntry::Dir(String::from("e")),
|
||||
LsEntry::File(ParseFile {
|
||||
size: 29116,
|
||||
name: String::from("f")
|
||||
}),
|
||||
LsEntry::File(ParseFile {
|
||||
size: 2557,
|
||||
name: String::from("g")
|
||||
}),
|
||||
LsEntry::File(ParseFile {
|
||||
size: 62596,
|
||||
name: String::from("h.lst")
|
||||
}),
|
||||
]),
|
||||
Command::Cd(String::from("e")),
|
||||
Command::Ls(vec![LsEntry::File(ParseFile {
|
||||
size: 584,
|
||||
name: String::from("i")
|
||||
}),]),
|
||||
Command::CdUp,
|
||||
Command::CdUp,
|
||||
Command::Cd(String::from("d")),
|
||||
Command::Ls(vec![
|
||||
LsEntry::File(ParseFile {
|
||||
size: 4060174,
|
||||
name: String::from("j")
|
||||
}),
|
||||
LsEntry::File(ParseFile {
|
||||
size: 8033020,
|
||||
name: String::from("d.log")
|
||||
}),
|
||||
LsEntry::File(ParseFile {
|
||||
size: 5626152,
|
||||
name: String::from("d.ext")
|
||||
}),
|
||||
LsEntry::File(ParseFile {
|
||||
size: 7214296,
|
||||
name: String::from("k")
|
||||
}),
|
||||
]),
|
||||
]
|
||||
)
|
||||
}
|
||||
#[test]
|
||||
fn test_commands_to_tree() {
|
||||
let input = vec![
|
||||
Command::CdRoot,
|
||||
Command::Ls(vec![
|
||||
LsEntry::Dir(String::from("a")),
|
||||
LsEntry::File(ParseFile {
|
||||
size: 14848514,
|
||||
name: String::from("b.txt"),
|
||||
}),
|
||||
LsEntry::File(ParseFile {
|
||||
size: 8504156,
|
||||
name: String::from("c.dat"),
|
||||
}),
|
||||
LsEntry::Dir(String::from("d")),
|
||||
]),
|
||||
Command::Cd(String::from("a")),
|
||||
Command::Ls(vec![
|
||||
LsEntry::Dir(String::from("e")),
|
||||
LsEntry::File(ParseFile {
|
||||
size: 29116,
|
||||
name: String::from("f"),
|
||||
}),
|
||||
LsEntry::File(ParseFile {
|
||||
size: 2557,
|
||||
name: String::from("g"),
|
||||
}),
|
||||
LsEntry::File(ParseFile {
|
||||
size: 62596,
|
||||
name: String::from("h.lst"),
|
||||
}),
|
||||
]),
|
||||
Command::Cd(String::from("e")),
|
||||
Command::Ls(vec![LsEntry::File(ParseFile {
|
||||
size: 584,
|
||||
name: String::from("i"),
|
||||
})]),
|
||||
Command::CdUp,
|
||||
Command::CdUp,
|
||||
Command::Cd(String::from("d")),
|
||||
Command::Ls(vec![
|
||||
LsEntry::File(ParseFile {
|
||||
size: 4060174,
|
||||
name: String::from("j"),
|
||||
}),
|
||||
LsEntry::File(ParseFile {
|
||||
size: 8033020,
|
||||
name: String::from("d.log"),
|
||||
}),
|
||||
LsEntry::File(ParseFile {
|
||||
size: 5626152,
|
||||
name: String::from("d.ext"),
|
||||
}),
|
||||
LsEntry::File(ParseFile {
|
||||
size: 7214296,
|
||||
name: String::from("k"),
|
||||
}),
|
||||
]),
|
||||
];
|
||||
let tree = commands_to_tree(input);
|
||||
println!("{}", tree);
|
||||
assert_eq!(Rc::clone(tree.deref()).borrow().get_total_size(), 48381165)
|
||||
}
|
||||
}
|
37
days/day07/src/part1.rs
Normal file
37
days/day07/src/part1.rs
Normal file
|
@ -0,0 +1,37 @@
|
|||
use crate::file_tree::*;
|
||||
|
||||
pub fn part1(input: NodeRef) -> usize {
|
||||
let dirs = input.get_all_dirs();
|
||||
dirs.iter()
|
||||
.map(|d| d.borrow().get_total_size())
|
||||
.filter(|s| *s <= 100000)
|
||||
.sum()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::{ops::Deref, rc::Rc};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_part1() {
|
||||
let mut root = NodeRef::new_dir("/".to_string());
|
||||
let mut cursor = root.add_node(Node::new_dir("a".to_string())).unwrap();
|
||||
cursor = cursor.add_dir("e".to_string()).unwrap();
|
||||
cursor.add_file("i".to_string(), 584).unwrap();
|
||||
cursor = Rc::clone(cursor.deref()).borrow().get_parent().unwrap();
|
||||
cursor.add_file("f".to_string(), 29116).unwrap();
|
||||
cursor.add_file("g".to_string(), 2557).unwrap();
|
||||
cursor.add_file("h.lst".to_string(), 62596).unwrap();
|
||||
cursor = Rc::clone(cursor.deref()).borrow().get_parent().unwrap();
|
||||
cursor.add_file("b.txt".to_string(), 14848514).unwrap();
|
||||
cursor.add_file("c.dat".to_string(), 8504156).unwrap();
|
||||
cursor = cursor.add_dir("d".to_string()).unwrap();
|
||||
cursor.add_file("j".to_string(), 4060174).unwrap();
|
||||
cursor.add_file("d.log".to_string(), 8033020).unwrap();
|
||||
cursor.add_file("d.ext".to_string(), 5626152).unwrap();
|
||||
cursor.add_file("k".to_string(), 7214296).unwrap();
|
||||
assert_eq!(part1(root), 95437);
|
||||
}
|
||||
}
|
44
days/day07/src/part2.rs
Normal file
44
days/day07/src/part2.rs
Normal file
|
@ -0,0 +1,44 @@
|
|||
use crate::file_tree::*;
|
||||
|
||||
const TOTAL_SPACE: usize = 70000000;
|
||||
const NEEDED_SPACE: usize = 30000000;
|
||||
|
||||
pub fn part2(input: NodeRef) -> usize {
|
||||
let used_space = input.borrow().get_total_size();
|
||||
let unused_space = TOTAL_SPACE - used_space;
|
||||
let space_to_free = NEEDED_SPACE - unused_space;
|
||||
let dirs = input.get_all_dirs();
|
||||
dirs.iter()
|
||||
.map(|d| d.borrow().get_total_size())
|
||||
.filter(|s| *s >= space_to_free)
|
||||
.min()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::{ops::Deref, rc::Rc};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_part2() {
|
||||
let mut root = NodeRef::new_dir("/".to_string());
|
||||
let mut cursor = root.add_node(Node::new_dir("a".to_string())).unwrap();
|
||||
cursor = cursor.add_dir("e".to_string()).unwrap();
|
||||
cursor.add_file("i".to_string(), 584).unwrap();
|
||||
cursor = Rc::clone(cursor.deref()).borrow().get_parent().unwrap();
|
||||
cursor.add_file("f".to_string(), 29116).unwrap();
|
||||
cursor.add_file("g".to_string(), 2557).unwrap();
|
||||
cursor.add_file("h.lst".to_string(), 62596).unwrap();
|
||||
cursor = Rc::clone(cursor.deref()).borrow().get_parent().unwrap();
|
||||
cursor.add_file("b.txt".to_string(), 14848514).unwrap();
|
||||
cursor.add_file("c.dat".to_string(), 8504156).unwrap();
|
||||
cursor = cursor.add_dir("d".to_string()).unwrap();
|
||||
cursor.add_file("j".to_string(), 4060174).unwrap();
|
||||
cursor.add_file("d.log".to_string(), 8033020).unwrap();
|
||||
cursor.add_file("d.ext".to_string(), 5626152).unwrap();
|
||||
cursor.add_file("k".to_string(), 7214296).unwrap();
|
||||
assert_eq!(part2(root), 24933642);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue