diff --git a/rs/src/y2022/d07.rs b/rs/src/y2022/d07.rs index a6055b5..f2eb8e2 100644 --- a/rs/src/y2022/d07.rs +++ b/rs/src/y2022/d07.rs @@ -1,15 +1,5 @@ use std::collections::HashMap; -enum LsItem { - File(usize, String), - Dir(String), -} - -enum Command { - Cd(String), - Ls(Vec), -} - enum Fs { Dir(HashMap), File(usize), @@ -24,11 +14,8 @@ impl Fs { } fn at_path(&mut self, path: &[String]) -> &mut Self { - let mut result = self; - for segment in path { - result = result.as_dir().get_mut(segment).unwrap(); - } - result + path.iter() + .fold(self, |p, s| p.as_dir().get_mut(s).unwrap()) } fn size(&self) -> usize { @@ -50,66 +37,25 @@ impl Fs { } } -fn command_chunks(input: &str) -> Vec<(String, Vec)> { - let mut lines = input.lines().peekable(); - let mut chunks = vec![]; - while let Some(command) = lines.next() { - assert!(command.starts_with("$ ")); - let mut items = vec![]; - while let Some(item) = lines.peek() { - if item.starts_with("$ ") { - break; - } - items.push(item.to_string()); - lines.next(); - } - chunks.push((command.to_string(), items)); - } - chunks -} - pub fn solve(input: String) { - // Parse commands - let commands = command_chunks(&input) - .into_iter() - .map(|(command, items)| { - if let Some(name) = command.strip_prefix("$ cd ") { - Command::Cd(name.to_string()) - } else { - assert_eq!(command, "$ ls"); - let ls_items = items - .into_iter() - .map(|item| { - let (left, name) = item.split_once(' ').unwrap(); - if left == "dir" { - LsItem::Dir(name.to_string()) - } else { - LsItem::File(left.parse::().unwrap(), name.to_string()) - } - }) - .collect::>(); - Command::Ls(ls_items) - } - }) - .collect::>(); - - // Build fs tree + // Parse commands and build fs tree let mut fs = Fs::Dir(HashMap::new()); let mut path = vec![]; - for command in commands { - match command { - Command::Cd(to) if to == "/" => path = vec![], - Command::Cd(to) if to == ".." => _ = path.pop(), // Learned a new trick - Command::Cd(to) => path.push(to), - Command::Ls(items) => { - for item in items { - let map = fs.at_path(&path).as_dir(); - match item { - LsItem::File(size, name) => map.insert(name, Fs::File(size)), - LsItem::Dir(name) => map.insert(name, Fs::Dir(HashMap::new())), - }; - } + for line in input.lines() { + if let Some(name) = line.strip_prefix("$ cd ") { + match name { + "/" => path.clear(), + ".." => _ = path.pop(), + _ => path.push(name.to_string()), } + } else if line == "$ ls" { + } else if let Some(name) = line.strip_prefix("dir ") { + let dir = Fs::Dir(HashMap::new()); + fs.at_path(&path).as_dir().insert(name.to_string(), dir); + } else { + let (size, name) = line.split_once(' ').unwrap(); + let file = Fs::File(size.parse().unwrap()); + fs.at_path(&path).as_dir().insert(name.to_string(), file); } } @@ -118,14 +64,8 @@ pub fn solve(input: String) { let part1 = dir_sizes.iter().filter(|s| **s <= 100000).sum::(); println!("Part 1: {part1}"); - let total_available = 70000000; - let required_for_update = 30000000; - let unused = total_available - fs.size(); - let free_at_least = required_for_update - unused; - let part2 = dir_sizes - .into_iter() - .filter(|s| *s >= free_at_least) - .min() - .unwrap(); + // 70000000 available, 30000000 required for update: We can't go over 40000000. + let min = fs.size() - 40000000; + let part2 = dir_sizes.into_iter().filter(|s| *s >= min).min().unwrap(); println!("Part 2: {part2}"); }