2022-7...
This commit is contained in:
		
							parent
							
								
									61268dc5ec
								
							
						
					
					
						commit
						93d7537f66
					
				
					 1 changed files with 169 additions and 0 deletions
				
			
		
							
								
								
									
										169
									
								
								src/bin/2022-7.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								src/bin/2022-7.rs
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,169 @@ | |||
| use eyes::parse; | ||||
| use itertools::Itertools; | ||||
| use std::{cell::RefCell, collections::HashMap, iter, rc::Rc}; | ||||
| 
 | ||||
| fn main() { | ||||
|     let input = aoc::input!(); | ||||
|     println!("part 1: {}", part1(&input)); | ||||
|     println!("part 1: {}", part2(&input)); | ||||
| } | ||||
| 
 | ||||
| type RefNode = Rc<RefCell<Node>>; | ||||
| #[derive(Default)] | ||||
| struct Node { | ||||
|     size: u64, | ||||
|     children: HashMap<String, RefNode>, | ||||
|     parent: Option<RefNode>, | ||||
| } | ||||
| 
 | ||||
| impl Node { | ||||
|     fn total_size(&self) -> u64 { | ||||
|         self.children | ||||
|             .values() | ||||
|             .map(|child| child.borrow().total_size()) | ||||
|             .sum::<u64>() | ||||
|             + self.size | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn all_dirs(n: RefNode) -> Box<dyn Iterator<Item = RefNode>> { | ||||
|     let children = n.borrow().children.values().cloned().collect::<Vec<_>>(); | ||||
| 
 | ||||
|     Box::new( | ||||
|         iter::once(n).chain( | ||||
|             children | ||||
|                 .into_iter() | ||||
|                 .filter_map(|c| { | ||||
|                     if c.borrow().size == 0 { | ||||
|                         Some(all_dirs(c)) | ||||
|                     } else { | ||||
|                         None | ||||
|                     } | ||||
|                 }) | ||||
|                 .flatten(), | ||||
|         ), | ||||
|     ) | ||||
| } | ||||
| 
 | ||||
| fn part1(input: &str) -> u64 { | ||||
|     let root = RefNode::default(); | ||||
|     let mut node = root.clone(); | ||||
| 
 | ||||
|     for line in input.lines() { | ||||
|         match line { | ||||
|             l if l.starts_with("$ cd") => { | ||||
|                 let dir = parse!(l, "$ cd {}", String); | ||||
|                 match dir.as_str() { | ||||
|                     "/" => continue, | ||||
|                     ".." => { | ||||
|                         let parent = node.borrow().parent.clone().unwrap(); | ||||
|                         node = parent; | ||||
|                     } | ||||
|                     _ => { | ||||
|                         let child = node.borrow_mut().children.entry(dir).or_default().clone(); | ||||
|                         node = child; | ||||
|                     } | ||||
|                 } | ||||
|             } // cd
 | ||||
|             l if l.starts_with("$ ls") => continue, // ls
 | ||||
|             l if l.starts_with("dir ") => { | ||||
|                 // dir entry
 | ||||
|                 let dir = parse!(l, "dir {}", String); | ||||
|                 let entry = node.borrow_mut().children.entry(dir).or_default().clone(); | ||||
|                 entry.borrow_mut().parent = Some(node.clone()); | ||||
|             } | ||||
|             l => { | ||||
|                 // file entry
 | ||||
|                 let (size, file) = parse!(l, "{} {}", u64, String); | ||||
|                 let entry = node.borrow_mut().children.entry(file).or_default().clone(); | ||||
|                 entry.borrow_mut().size = size; | ||||
|                 entry.borrow_mut().parent = Some(node.clone()); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     all_dirs(root) | ||||
|         .map(|d| d.borrow().total_size()) | ||||
|         .filter(|&s| s <= 100_000) | ||||
|         .sum::<u64>() | ||||
| } | ||||
| 
 | ||||
| fn part2(input: &str) -> u64 { | ||||
|     let root = RefNode::default(); | ||||
|     let mut node = root.clone(); | ||||
| 
 | ||||
|     for line in input.lines() { | ||||
|         match line { | ||||
|             l if l.starts_with("$ cd") => { | ||||
|                 let dir = parse!(l, "$ cd {}", String); | ||||
|                 match dir.as_str() { | ||||
|                     "/" => continue, | ||||
|                     ".." => { | ||||
|                         let parent = node.borrow().parent.clone().unwrap(); | ||||
|                         node = parent; | ||||
|                     } | ||||
|                     _ => { | ||||
|                         let child = node.borrow_mut().children.entry(dir).or_default().clone(); | ||||
|                         node = child; | ||||
|                     } | ||||
|                 } | ||||
|             } // cd
 | ||||
|             l if l.starts_with("$ ls") => continue, // ls
 | ||||
|             l if l.starts_with("dir ") => { | ||||
|                 // dir entry
 | ||||
|                 let dir = parse!(l, "dir {}", String); | ||||
|                 let entry = node.borrow_mut().children.entry(dir).or_default().clone(); | ||||
|                 entry.borrow_mut().parent = Some(node.clone()); | ||||
|             } | ||||
|             l => { | ||||
|                 // file entry
 | ||||
|                 let (size, file) = parse!(l, "{} {}", u64, String); | ||||
|                 let entry = node.borrow_mut().children.entry(file).or_default().clone(); | ||||
|                 entry.borrow_mut().size = size; | ||||
|                 entry.borrow_mut().parent = Some(node.clone()); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     let free_space = 70000000 - root.borrow().total_size(); | ||||
|     all_dirs(root) | ||||
|         .map(|d| d.borrow().total_size()) | ||||
|         .filter(|&s| s >= 30000000 - free_space) | ||||
|         .min() | ||||
|         .unwrap() | ||||
| } | ||||
| 
 | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use super::*; | ||||
| 
 | ||||
|     #[test] | ||||
|     fn examples() { | ||||
|         let example = r#"$ 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"#;
 | ||||
| 
 | ||||
|         assert_eq!(part1(example), 95437); | ||||
|         assert_eq!(part2(example), 24933642); | ||||
|     } | ||||
| } | ||||
		Loading…
	
		Reference in a new issue