let s1: Shape = Shape::parse(l[0]);
let s2 = match l[1] {
"X" => match s1 { Shape::Rock => Shape::Scissors, Shape::Paper => Shape::Rock, Shape::Scissors => Shape::Paper, }, // Need to lose.
- "Z" => match s1 { Shape::Rock => Shape::Paper, Shape::Paper => Shape::Scissors, Shape::Scissors => Shape::Rock, }, // Need to win
+ "Z" => match s1 { Shape::Rock => Shape::Paper, Shape::Paper => Shape::Scissors, Shape::Scissors => Shape::Rock, }, // Need to win.
_ => s1, // Draw.
};
--- /dev/null
+use std::str::Lines;
+
+#[derive(Debug)]
+pub struct Dir {
+ files: Vec<i64>,
+ dirs: Vec<Dir>,
+}
+
+impl Dir {
+ fn new() -> Dir {
+ Dir { files: Vec::new(), dirs: Vec::new() }
+ }
+
+ fn get_file_size(&self) -> i64 {
+ self.files.iter().sum()
+ }
+
+ pub fn dir_sizes<P>(&self, predicate: P, result: &mut Vec<i64>) -> i64
+ where
+ P: Fn(i64) -> bool + Copy,
+ {
+ let size = self.get_file_size() + self.dirs.iter().map(|dir| dir.dir_sizes(predicate, result)).sum::<i64>();
+ if predicate(size) {
+ result.push(size)
+ }
+ size
+ }
+}
+
+pub fn parse(input: &str) -> Dir {
+ fn create_dir(lines: &mut Lines) -> Dir {
+ let mut dir = Dir::new();
+ while let Some(l) = lines.next() {
+ let l: Vec<&str> = l.split(' ').collect();
+ if l[0] == "$" {
+ if l[1] == "cd" {
+ if l[2] == ".." {
+ return dir;
+ } else {
+ let child = create_dir(lines);
+ dir.dirs.push(child);
+ }
+ }
+ } else if l[0] != "dir" {
+ dir.files.push(l[0].parse().unwrap());
+ }
+ }
+ dir
+ }
+ let mut lines = input.lines();
+ lines.next(); // First line is always the root.
+ create_dir(&mut lines)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn part1() {
+ let commands = "$ 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";
+ let root = parse(commands);
+ let mut sizes: Vec<i64> = Vec::new();
+ root.dir_sizes(|size| size <= 100_000, &mut sizes);
+ assert_eq!(sizes.iter().sum::<i64>(), 95_437);
+ }
+
+ #[test]
+ fn part2() {
+ let commands = "$ 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";
+ let root = parse(commands);
+
+ let root_size = root.dir_sizes(|size| size <= 100_000, &mut Vec::new());
+
+ let required = root_size - (70_000_000 - 30_000_000);
+ let mut sizes: Vec<i64> = Vec::new();
+ root.dir_sizes(|size| size >= required, &mut sizes);
+
+ assert_eq!(*sizes.iter().min().unwrap(), 24933642);
+ }
+}
\ No newline at end of file
mod day04;
mod day05;
mod day06;
+mod day07;
fn day01() -> String {
let f = fs::File::open("data/day01.input").unwrap();
format!("part1: {}, part2: {}", day06::first_marker_pos(&signals, 4), day06::first_marker_pos(&signals, 14))
}
+fn day07() -> String {
+ let root = day07::parse(&fs::read_to_string("data/day07.input").unwrap());
+
+ let (root_size, sum_part1 ) = {
+ let mut sizes: Vec<i64> = Vec::new();
+ (root.dir_sizes(|size| size <= 100_000, &mut sizes), sizes.iter().sum::<i64>())
+ };
+
+ let min_part2 = {
+ let to_free = root_size - (70_000_000 - 30_000_000);
+ let mut sizes: Vec<i64> = Vec::new();
+ root.dir_sizes(|size| size >= to_free, &mut sizes);
+ *sizes.iter().min().unwrap()
+ };
+
+ format!("part1: {}, part2: {}", sum_part1, min_part2)
+}
+
fn format_micros(t: u128) -> String {
if t < 10_000 {
format!("{} μs", t)
day04,
day05,
day06,
+ day07,
);
let args: Vec<String> = env::args().skip(1).collect();