[rs] Simplify 2022_07

This commit is contained in:
Joscha 2022-12-07 13:57:57 +01:00
parent 5e74d92d43
commit dd5cf6019d

View file

@ -1,15 +1,5 @@
use std::collections::HashMap; use std::collections::HashMap;
enum LsItem {
File(usize, String),
Dir(String),
}
enum Command {
Cd(String),
Ls(Vec<LsItem>),
}
enum Fs { enum Fs {
Dir(HashMap<String, Fs>), Dir(HashMap<String, Fs>),
File(usize), File(usize),
@ -24,11 +14,8 @@ impl Fs {
} }
fn at_path(&mut self, path: &[String]) -> &mut Self { fn at_path(&mut self, path: &[String]) -> &mut Self {
let mut result = self; path.iter()
for segment in path { .fold(self, |p, s| p.as_dir().get_mut(s).unwrap())
result = result.as_dir().get_mut(segment).unwrap();
}
result
} }
fn size(&self) -> usize { fn size(&self) -> usize {
@ -50,66 +37,25 @@ impl Fs {
} }
} }
fn command_chunks(input: &str) -> Vec<(String, Vec<String>)> {
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) { pub fn solve(input: String) {
// Parse commands // Parse commands and build fs tree
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::<usize>().unwrap(), name.to_string())
}
})
.collect::<Vec<_>>();
Command::Ls(ls_items)
}
})
.collect::<Vec<_>>();
// Build fs tree
let mut fs = Fs::Dir(HashMap::new()); let mut fs = Fs::Dir(HashMap::new());
let mut path = vec![]; let mut path = vec![];
for command in commands { for line in input.lines() {
match command { if let Some(name) = line.strip_prefix("$ cd ") {
Command::Cd(to) if to == "/" => path = vec![], match name {
Command::Cd(to) if to == ".." => _ = path.pop(), // Learned a new trick "/" => path.clear(),
Command::Cd(to) => path.push(to), ".." => _ = path.pop(),
Command::Ls(items) => { _ => path.push(name.to_string()),
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())),
};
}
} }
} 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::<usize>(); let part1 = dir_sizes.iter().filter(|s| **s <= 100000).sum::<usize>();
println!("Part 1: {part1}"); println!("Part 1: {part1}");
let total_available = 70000000; // 70000000 available, 30000000 required for update: We can't go over 40000000.
let required_for_update = 30000000; let min = fs.size() - 40000000;
let unused = total_available - fs.size(); let part2 = dir_sizes.into_iter().filter(|s| *s >= min).min().unwrap();
let free_at_least = required_for_update - unused;
let part2 = dir_sizes
.into_iter()
.filter(|s| *s >= free_at_least)
.min()
.unwrap();
println!("Part 2: {part2}"); println!("Part 2: {part2}");
} }