broken implementation of 7.1
This commit is contained in:
		
							
								
								
									
										181
									
								
								2022/src/day7.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								2022/src/day7.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,181 @@
 | 
			
		||||
use std::collections::HashMap;
 | 
			
		||||
 | 
			
		||||
use lazy_static::lazy_static;
 | 
			
		||||
use regex::Regex;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct Directory {
 | 
			
		||||
    name: String,
 | 
			
		||||
    children: Vec<Node>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct File {
 | 
			
		||||
    name: String,
 | 
			
		||||
    size: usize,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
enum Node {
 | 
			
		||||
    Branch(Directory),
 | 
			
		||||
    Leaf(File),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
lazy_static! {
 | 
			
		||||
    static ref CMD_CD: Regex = Regex::new(r"^\$ cd (\w+)$").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();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct DirListing {
 | 
			
		||||
    name: String,
 | 
			
		||||
    children: Vec<usize>,
 | 
			
		||||
    parent: Option<usize>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum NodeListing {
 | 
			
		||||
    Branch(DirListing),
 | 
			
		||||
    Leaf(File),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
fn build_map(data: &str) -> Result<HashMap<usize, NodeListing>, String> {
 | 
			
		||||
    let root = DirListing {
 | 
			
		||||
        name: "".to_string(),
 | 
			
		||||
        children: vec![],
 | 
			
		||||
        parent: None,
 | 
			
		||||
    };
 | 
			
		||||
    let mut map = HashMap::new();
 | 
			
		||||
    map.insert(0, NodeListing::Branch(root));
 | 
			
		||||
 | 
			
		||||
    let mut stack: Vec<usize> = vec![];
 | 
			
		||||
    stack.push(0);
 | 
			
		||||
 | 
			
		||||
    '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 name == ".." {
 | 
			
		||||
                stack.pop();
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            let current_dir = match map.get(&stack.last().unwrap()).unwrap() {
 | 
			
		||||
                NodeListing::Branch(dir) => dir,
 | 
			
		||||
                _ => unreachable!(),
 | 
			
		||||
            };
 | 
			
		||||
            for id in current_dir.children {
 | 
			
		||||
                let child_name = match map.get(&id).unwrap() {
 | 
			
		||||
                    NodeListing::Branch(dir) => dir.name,
 | 
			
		||||
                    NodeListing::Leaf(file) => file.name,
 | 
			
		||||
                };
 | 
			
		||||
                if child_name == name {
 | 
			
		||||
                    stack.push(id);
 | 
			
		||||
                    continue 'lines;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            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() {
 | 
			
		||||
            let parent_id = stack.last().unwrap();
 | 
			
		||||
            let parent = match map.get_mut(parent_id).unwrap() {
 | 
			
		||||
                NodeListing::Branch(dir) => dir,
 | 
			
		||||
                _ => unreachable!(),
 | 
			
		||||
            };
 | 
			
		||||
            let dir = DirListing {
 | 
			
		||||
                name: m.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);
 | 
			
		||||
            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::<usize>()
 | 
			
		||||
                .map_err(|_e| format!("Invalid file size: {}", line.to_string()))?;
 | 
			
		||||
 | 
			
		||||
            let file_id = map.len();
 | 
			
		||||
            let file = File {name, size};
 | 
			
		||||
            map.insert(file_id, NodeListing::Leaf(file));
 | 
			
		||||
 | 
			
		||||
            let parent = match map.get_mut(stack.last().unwrap()).unwrap() {
 | 
			
		||||
                NodeListing::Branch(dir) => dir,
 | 
			
		||||
                _ => unreachable!(),
 | 
			
		||||
            };
 | 
			
		||||
            parent.children.push(file_id);
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return Err(format!("Could not interpret line: {line}"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Ok(map)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
fn build_tree(map: &HashMap<usize, NodeListing>, 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() {
 | 
			
		||||
            NodeListing::Leaf(file) => {
 | 
			
		||||
                root_children.push(Node::Leaf(file));
 | 
			
		||||
            },
 | 
			
		||||
            NodeListing::Branch(dir_listing) => {
 | 
			
		||||
                let dir = build_tree(map, child_id);
 | 
			
		||||
                root_children.push(Node::Branch(dir))
 | 
			
		||||
            },
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Directory {
 | 
			
		||||
        name: root_listing.name.clone(),
 | 
			
		||||
        children: root_children,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
fn get_sizes(root: &Directory, mut sizes: Vec<usize>) -> (usize, Vec<usize>) {
 | 
			
		||||
    let dir_size = 0;
 | 
			
		||||
 | 
			
		||||
    let mut returned_sizes;
 | 
			
		||||
    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;
 | 
			
		||||
                dir_size += child_size;
 | 
			
		||||
            },
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    returned_sizes.push(dir_size);
 | 
			
		||||
    returned_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 part1_sizes = dir_sizes.iter()
 | 
			
		||||
        .filter(|s| s <= 100000)
 | 
			
		||||
        .sum();
 | 
			
		||||
 | 
			
		||||
    println!("Part 1: {part1_sizes}");
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user