Day 7, puzzle 1
This commit is contained in:
parent
a446a05c07
commit
bedf4a790a
|
@ -0,0 +1,20 @@
|
|||
use aoc22::{day7, util};
|
||||
|
||||
const MAX_SIZE: usize = 100000;
|
||||
|
||||
pub fn main() {
|
||||
let root = day7::parse_cmdline(&util::parse_input());
|
||||
|
||||
let mut total_size = 0;
|
||||
for child in root.borrow().all_children() {
|
||||
let c = &*child.borrow();
|
||||
if let day7::Node::Dir { .. } = c {
|
||||
let size = c.size();
|
||||
if size <= MAX_SIZE {
|
||||
total_size += size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println!("Total size of small directories: {}", total_size);
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
use std::{cell::RefCell, collections::HashMap, rc::Rc, vec};
|
||||
|
||||
use regex::Regex;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Node {
|
||||
File {
|
||||
name: String,
|
||||
size: usize,
|
||||
},
|
||||
Dir {
|
||||
name: String,
|
||||
children: HashMap<String, Rc<RefCell<Node>>>,
|
||||
parent: Option<Rc<RefCell<Node>>>,
|
||||
},
|
||||
}
|
||||
|
||||
impl Node {
|
||||
pub fn print(&self, level: usize) {
|
||||
match self {
|
||||
Node::File { name, size } => println!("{0:1$}| {2}\t{3}", "", level * 2, name, size),
|
||||
Node::Dir { name, children, .. } => {
|
||||
println!("{0:1$}| {2}", "", level * 2, name);
|
||||
println!("{0:1$} \\", "", level * 2);
|
||||
for (_, child) in children {
|
||||
(**child).borrow().print(level + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn size(&self) -> usize {
|
||||
match self {
|
||||
Node::File { size, .. } => *size,
|
||||
Node::Dir { children, .. } => children.iter().map(|(_, c)| (**c).borrow().size()).sum(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_children(&self) -> Vec<Rc<RefCell<Node>>> {
|
||||
match self {
|
||||
Node::File { .. } => vec![],
|
||||
Node::Dir { children, .. } => {
|
||||
let mut result: Vec<Rc<RefCell<Node>>> = children.values().map(Rc::clone).collect();
|
||||
for (_, child) in children {
|
||||
result.append(&mut (**child).borrow().all_children());
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum ParseState {
|
||||
Command,
|
||||
ListOutput,
|
||||
}
|
||||
|
||||
pub fn parse_cmdline(input: &String) -> Rc<RefCell<Node>> {
|
||||
let lines = input.lines();
|
||||
let mut state = ParseState::Command;
|
||||
let root = Rc::new(RefCell::new(Node::Dir {
|
||||
name: "/".to_owned(),
|
||||
children: HashMap::new(),
|
||||
parent: None,
|
||||
}));
|
||||
let mut current_node = root.clone();
|
||||
|
||||
for line in lines {
|
||||
if line.starts_with("$") {
|
||||
state = ParseState::Command;
|
||||
}
|
||||
|
||||
match state {
|
||||
ParseState::Command => {
|
||||
let cmd = parse_command(line);
|
||||
match cmd {
|
||||
Command::ChangeDirRoot => current_node = root.clone(),
|
||||
Command::ChangeDirParent => {
|
||||
let next_node = if let Node::Dir { parent, .. } = &*(*current_node).borrow()
|
||||
{
|
||||
match parent {
|
||||
Some(p) => p.clone(),
|
||||
None => root.clone(),
|
||||
}
|
||||
// parent.unwrap_or(root.clone()).clone()
|
||||
} else {
|
||||
panic!("Current node is a file!?");
|
||||
};
|
||||
current_node = next_node;
|
||||
}
|
||||
Command::ChangeDirChild(name) => {
|
||||
let next_node =
|
||||
if let Node::Dir { children, .. } = &*(*current_node).borrow() {
|
||||
children.get(name.as_str()).unwrap().clone()
|
||||
} else {
|
||||
panic!("Current node is a file!?");
|
||||
};
|
||||
current_node = next_node;
|
||||
}
|
||||
Command::List => state = ParseState::ListOutput,
|
||||
}
|
||||
}
|
||||
ParseState::ListOutput => {
|
||||
let node = parse_list_output(line, ¤t_node);
|
||||
if let Node::Dir { children, .. } = &mut *(*current_node).borrow_mut() {
|
||||
let n = match &node {
|
||||
Node::File { name, .. } => name,
|
||||
Node::Dir { name, .. } => name,
|
||||
};
|
||||
children.insert(n.clone(), Rc::new(RefCell::new(node)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
root
|
||||
}
|
||||
|
||||
enum Command {
|
||||
ChangeDirRoot,
|
||||
ChangeDirParent,
|
||||
ChangeDirChild(String),
|
||||
List,
|
||||
}
|
||||
|
||||
fn parse_command(line: &str) -> Command {
|
||||
let re = Regex::new(r"^\$ (cd|ls)(?: (.*))?$").unwrap();
|
||||
let captures = re.captures(line).unwrap();
|
||||
if captures.get(1).unwrap().as_str() == "ls" {
|
||||
assert!(captures.get(2) == None);
|
||||
Command::List
|
||||
} else {
|
||||
let dir = captures.get(2).unwrap().as_str();
|
||||
if dir == "/" {
|
||||
Command::ChangeDirRoot
|
||||
} else if dir == ".." {
|
||||
Command::ChangeDirParent
|
||||
} else {
|
||||
Command::ChangeDirChild(dir.to_owned())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_list_output(line: &str, parent: &Rc<RefCell<Node>>) -> Node {
|
||||
let (first, second) = line.split_once(' ').unwrap();
|
||||
if first == "dir" {
|
||||
Node::Dir {
|
||||
name: second.to_owned(),
|
||||
children: HashMap::new(),
|
||||
parent: Some(parent.clone()),
|
||||
}
|
||||
} else {
|
||||
Node::File {
|
||||
name: second.to_owned(),
|
||||
size: first.parse().unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,4 +4,5 @@ pub mod day3;
|
|||
pub mod day4;
|
||||
pub mod day5;
|
||||
pub mod day6;
|
||||
pub mod day7;
|
||||
pub mod util;
|
||||
|
|
Loading…
Reference in New Issue