Solve day 7
This commit is contained in:
parent
93ee369010
commit
b97e512d98
3 changed files with 1203 additions and 0 deletions
23
input/07-test
Normal file
23
input/07-test
Normal file
|
@ -0,0 +1,23 @@
|
|||
$ 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
|
128
src/bin/07.rs
Normal file
128
src/bin/07.rs
Normal file
|
@ -0,0 +1,128 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
use aoc2022::*;
|
||||
|
||||
const INPUT: &str = include_str!("../../input/07");
|
||||
|
||||
fn main() {
|
||||
let tree = Tree::from_input();
|
||||
solved_level_1(tree.part1());
|
||||
solved_level_2(tree.part2());
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Tree(Vec<Node>);
|
||||
|
||||
impl Tree {
|
||||
fn from_input() -> Self {
|
||||
let mut tree = vec![Node::directory(0)];
|
||||
let mut current = 0;
|
||||
|
||||
// Skip 1 skips the initial "cd /".
|
||||
let input = INPUT.lines().filter_map(|l| l.parse::<Line>().ok()).skip(1);
|
||||
|
||||
for line in input {
|
||||
match line {
|
||||
Line::CommandUp => current = tree[current].parent(),
|
||||
Line::CommandInto => {
|
||||
let handle = tree.len();
|
||||
tree.push(Node::directory(current));
|
||||
tree[current].add_child(handle);
|
||||
current = handle;
|
||||
}
|
||||
Line::File(size) => {
|
||||
let handle = tree.len();
|
||||
tree.push(Node::file(current, size));
|
||||
tree[current].add_child(handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Self(tree)
|
||||
}
|
||||
|
||||
fn dir_sizes(&self) -> impl Iterator<Item = usize> + '_ {
|
||||
self.0
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(i, node)| match node {
|
||||
Node::Directory { .. } => Some(i),
|
||||
Node::File { .. } => None,
|
||||
})
|
||||
.map(|i| self.sum_size(i))
|
||||
}
|
||||
|
||||
fn part1(&self) -> usize {
|
||||
self.dir_sizes().filter(|s| *s <= 100000).sum()
|
||||
}
|
||||
|
||||
fn part2(&self) -> usize {
|
||||
let used = self.sum_size(0);
|
||||
let unused = 70000000 - used;
|
||||
let needed = 30000000 - unused;
|
||||
|
||||
self.dir_sizes().filter(|s| *s >= needed).min().unwrap()
|
||||
}
|
||||
|
||||
fn sum_size(&self, i: usize) -> usize {
|
||||
match &self.0[i] {
|
||||
Node::Directory { children, .. } => children.iter().map(|c| self.sum_size(*c)).sum(),
|
||||
Node::File { size, .. } => *size,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Node {
|
||||
Directory { parent: usize, children: Vec<usize> },
|
||||
File { parent: usize, size: usize },
|
||||
}
|
||||
|
||||
impl Node {
|
||||
fn add_child(&mut self, child: usize) {
|
||||
match self {
|
||||
Node::Directory { children, .. } => children.push(child),
|
||||
Node::File { .. } => panic!("cannot add child to file"),
|
||||
}
|
||||
}
|
||||
fn directory(parent: usize) -> Self {
|
||||
Self::Directory {
|
||||
parent,
|
||||
children: Vec::new(),
|
||||
}
|
||||
}
|
||||
fn file(parent: usize, size: usize) -> Self {
|
||||
Self::File { parent, size }
|
||||
}
|
||||
fn parent(&self) -> usize {
|
||||
match self {
|
||||
Node::Directory { parent, .. } => *parent,
|
||||
Node::File { parent, .. } => *parent,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Line {
|
||||
CommandUp,
|
||||
CommandInto,
|
||||
File(usize),
|
||||
}
|
||||
|
||||
impl FromStr for Line {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
if s == "$ cd .." {
|
||||
Ok(Self::CommandUp)
|
||||
} else if s.starts_with("$ cd ") {
|
||||
Ok(Self::CommandInto)
|
||||
} else if s == "$ ls" || s.starts_with("dir") {
|
||||
// Ignore ls and directories
|
||||
Err(())
|
||||
} else {
|
||||
let size: usize = s.split(' ').next().unwrap().parse().unwrap();
|
||||
Ok(Self::File(size))
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue