aboutsummaryrefslogtreecommitdiff
path: root/2022/src/day07.rs
diff options
context:
space:
mode:
Diffstat (limited to '2022/src/day07.rs')
-rw-r--r--2022/src/day07.rs110
1 files changed, 110 insertions, 0 deletions
diff --git a/2022/src/day07.rs b/2022/src/day07.rs
new file mode 100644
index 0000000..88bb647
--- /dev/null
+++ b/2022/src/day07.rs
@@ -0,0 +1,110 @@
+mod utils;
+use utils::read_input;
+
+fn main() {
+ let input = read_input();
+
+ let mut unused = 0;
+ let mut sum_under_threshold = 0;
+
+ for size in DirectorySizes::new(&input) {
+ if size < 100_000 {
+ sum_under_threshold += size;
+ }
+ unused = 70_000_000 - size;
+ }
+
+ println!("Part 1: {}", sum_under_threshold);
+ let deficit = 30_000_000 - unused;
+ println!(
+ "Part 2: {}",
+ DirectorySizes::new(&input)
+ .filter(|x| *x > deficit)
+ .min()
+ .unwrap()
+ );
+}
+
+struct DirectorySizes<'a> {
+ lines: std::str::Lines<'a>,
+ directory_stack: [usize; 64],
+ stack_top: usize,
+}
+
+impl<'a> DirectorySizes<'a> {
+ fn new(input: &'a str) -> Self {
+ let mut lines = input.lines();
+ assert_eq!(lines.next(), Some("$ cd /"));
+
+ DirectorySizes {
+ lines,
+ directory_stack: [0; 64],
+ stack_top: 0,
+ }
+ }
+}
+
+impl Iterator for DirectorySizes<'_> {
+ type Item = usize;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ for line in self.lines.by_ref() {
+ let line: Line = line.into();
+
+ match line {
+ Line::Cd(up) => {
+ if up {
+ self.directory_stack[self.stack_top - 1] +=
+ self.directory_stack[self.stack_top];
+ self.stack_top -= 1;
+ return Some(self.directory_stack[self.stack_top + 1]);
+ } else {
+ self.stack_top += 1;
+ self.directory_stack[self.stack_top] = 0;
+ }
+ }
+ Line::FileSize(size) => {
+ self.directory_stack[self.stack_top] += size;
+ }
+ Line::Ls => (),
+ Line::Dir => (),
+ };
+ }
+
+ if self.stack_top > 0 {
+ self.directory_stack[self.stack_top - 1] += self.directory_stack[self.stack_top];
+ self.stack_top -= 1;
+ Some(self.directory_stack[self.stack_top + 1])
+ } else if self.directory_stack[0] != 0 {
+ Some(std::mem::replace(&mut self.directory_stack[0], 0))
+ } else {
+ None
+ }
+ }
+}
+
+#[derive(Debug, Clone, Copy)]
+enum Line {
+ /// True = .., False = other
+ Cd(bool),
+ Ls,
+ FileSize(usize),
+ Dir,
+}
+
+impl From<&str> for Line {
+ fn from(value: &str) -> Self {
+ if value.starts_with("$ cd ") {
+ let mut args = value.split("cd ");
+ args.next().unwrap();
+ Line::Cd(args.next().unwrap() == "..")
+ } else if value.starts_with("$ ls") {
+ Line::Ls
+ } else if value.starts_with("dir") {
+ Line::Dir
+ } else {
+ let num_index = value.chars().take_while(|chr| chr.is_numeric()).count();
+ Line::FileSize(value[..num_index].parse().unwrap())
+ }
+ }
+}