diff --git a/2022/src/day7.rs b/2022/src/day7.rs index be5585a..46d8736 100644 --- a/2022/src/day7.rs +++ b/2022/src/day7.rs @@ -24,10 +24,10 @@ enum Node { lazy_static! { - static ref CMD_CD: Regex = Regex::new(r"^\$ cd (\w+)$").unwrap(); + static ref CMD_CD: Regex = Regex::new(r"^\$ cd (\S+)$").unwrap(); static ref CMD_LS: Regex = Regex::new(r"^\$ ls$").unwrap(); - static ref DIR_LISTING: Regex = Regex::new(r"^dir (\w+)$").unwrap(); - static ref FILE_LISTING: Regex = Regex::new(r"^(\d+) (\w+)$").unwrap(); + static ref DIR_LISTING: Regex = Regex::new(r"^dir (\S+)$").unwrap(); + static ref FILE_LISTING: Regex = Regex::new(r"^(\d+) (\S+)$").unwrap(); } @@ -58,8 +58,13 @@ fn build_map(data: &str) -> Result, String> { 'lines: for line in data.trim().lines() { if CMD_LS.is_match(line) {continue;} - if let Some(m) = CMD_CD.find_iter(line).next() { - let name = m.as_str(); + if let Some(c) = CMD_CD.captures(line) { + let name = c.get(1).unwrap().as_str(); + if name == "/" { + stack.truncate(1); + continue; + } + if name == ".." { stack.pop(); continue; @@ -69,13 +74,13 @@ fn build_map(data: &str) -> Result, String> { NodeListing::Branch(dir) => dir, _ => unreachable!(), }; - for id in current_dir.children { + for id in ¤t_dir.children { let child_name = match map.get(&id).unwrap() { - NodeListing::Branch(dir) => dir.name, - NodeListing::Leaf(file) => file.name, + NodeListing::Branch(dir) => &dir.name, + NodeListing::Leaf(file) => &file.name, }; if child_name == name { - stack.push(id); + stack.push(*id); continue 'lines; } } @@ -83,28 +88,27 @@ fn build_map(data: &str) -> Result, String> { return Err(format!("Attempted to cd into directory before ls-ing it: {}", line.to_string())); } - if let Some(m) = DIR_LISTING.find_iter(line).next() { + if let Some(c) = DIR_LISTING.captures(line) { let parent_id = stack.last().unwrap(); + let child_id = map.len(); let parent = match map.get_mut(parent_id).unwrap() { NodeListing::Branch(dir) => dir, _ => unreachable!(), }; + parent.children.push(child_id); + let dir = DirListing { - name: m.as_str().to_string(), + name: c.get(1).unwrap().as_str().to_string(), children: vec![], parent: Some(*parent_id), }; - // this is safe as long as we never remove anything from the map while we're building it - let dir_id = map.len(); - map.insert(dir_id, NodeListing::Branch(dir)); - parent.children.push(dir_id); + map.insert(child_id, NodeListing::Branch(dir)); continue; } - let matches = FILE_LISTING.find_iter(line); - if let (Some(s), Some(n)) = (matches.next(), matches.next()) { - let name = n.as_str().to_string(); - let size = s.as_str().parse::() + if let Some(c) = FILE_LISTING.captures(line) { + let name = c.get(2).unwrap().as_str().to_string(); + let size = c.get(1).unwrap().as_str().parse::() .map_err(|_e| format!("Invalid file size: {}", line.to_string()))?; let file_id = map.len(); @@ -126,16 +130,15 @@ fn build_map(data: &str) -> Result, String> { } -fn build_tree(map: &HashMap, root:&DirListing) -> Directory { - let root_listing = map.get(&root_id).unwrap(); - let root_children = Vec::new(); - for child_id in root_listing.children { - match map.get(&child_id).unwrap() { +fn build_tree(map: &mut HashMap, root_listing: &DirListing) -> Directory { + let mut root_children = Vec::new(); + for child_id in &root_listing.children { + match map.remove(&child_id).unwrap() { NodeListing::Leaf(file) => { root_children.push(Node::Leaf(file)); }, NodeListing::Branch(dir_listing) => { - let dir = build_tree(map, child_id); + let dir = build_tree(map, &dir_listing); root_children.push(Node::Branch(dir)) }, } @@ -149,33 +152,78 @@ fn build_tree(map: &HashMap, root:&DirListing) -> Directory fn get_sizes(root: &Directory, mut sizes: Vec) -> (usize, Vec) { - let dir_size = 0; + let mut dir_size = 0; - let mut returned_sizes; - for child in root.children { + for child in &root.children { match child { Node::Leaf(file) => dir_size += file.size, Node::Branch(dir) => { let (child_size, rs) = get_sizes(dir, sizes); - returned_sizes = rs; + sizes = rs; dir_size += child_size; }, } } - returned_sizes.push(dir_size); - returned_sizes + sizes.push(dir_size); + (dir_size, sizes) } fn main() -> Result<(), String> { - let map = build_map(data); - let tree = build_tree(map, 0); - let (_total_size, dir_sizes) = get_sizes(&tree, vec![]); + let mut map = build_map(DATA)?; + let root = match map.remove(&0).unwrap() { + NodeListing::Branch(dir) => dir, + _ => unreachable!(), + }; - let part1_sizes = dir_sizes.iter() - .filter(|s| s <= 100000) + let tree = build_tree(&mut map, &root); + let (total_size, dir_sizes) = get_sizes(&tree, vec![]); + + let part1_sizes: usize = dir_sizes.iter() + .filter(|&&s| s <= 100000) .sum(); - println!("Part 1: {part1_sizes}"); + + let available = 70_000_000 - total_size; + if available >= 30_000_000 { + return Err("Weird, there's already enough space available".to_string()); + } + let target_size = 30_000_000 - available; + + let delete_size = dir_sizes.iter() + .filter(|&&s| s >= target_size) + .min() + .unwrap(); + println!("Part 2: {delete_size}"); + + Ok(()) } + + +const DATA: &'static str = include_str!("../data/day7.txt"); +// const DATA: &'static str = " +// $ cd / +// $ ls +// dir a +// 14848514 b.txt +// 8504156 c.dat +// dir d +// $ cd a +// $ ls +// dir e +// 29116 f +// 2557 g +// 62596 h.lst +// $ cd e +// $ ls +// 584 i +// $ cd .. +// $ cd .. +// $ cd d +// $ ls +// 4060174 j +// 8033020 d.log +// 5626152 d.ext +// 7214296 k +// ";