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 day4;
 | 
				
			||||||
pub mod day5;
 | 
					pub mod day5;
 | 
				
			||||||
pub mod day6;
 | 
					pub mod day6;
 | 
				
			||||||
 | 
					pub mod day7;
 | 
				
			||||||
pub mod util;
 | 
					pub mod util;
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user