Day 7, puzzle 1
This commit is contained in:
		
							
								
								
									
										20
									
								
								src/bin/d7p1.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/bin/d7p1.rs
									
									
									
									
									
										Normal file
									
								
							@ -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);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										158
									
								
								src/day7.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								src/day7.rs
									
									
									
									
									
										Normal file
									
								
							@ -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;
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user