Add solution for 2022 day 07

This commit is contained in:
Patrick Auernig 2022-12-09 13:38:53 +01:00
parent 500d952ee3
commit 2ec8b3934e
11 changed files with 1273 additions and 2 deletions

4
2022/Cargo.lock generated
View File

@ -32,6 +32,10 @@ dependencies = [
"itertools", "itertools",
] ]
[[package]]
name = "aoc-2022-07"
version = "0.1.0"
[[package]] [[package]]
name = "either" name = "either"
version = "1.8.0" version = "1.8.0"

View File

@ -6,6 +6,7 @@ members = [
"./day-04", "./day-04",
"./day-05", "./day-05",
"./day-06", "./day-06",
"./day-07",
] ]

View File

@ -10,7 +10,7 @@
| 04 | ✓ | ✓ | [Rust] | | 04 | ✓ | ✓ | [Rust] |
| 05 | ✓ | ✓ | [Rust] | | 05 | ✓ | ✓ | [Rust] |
| 06 | ✓ | ✓ | [Rust] | | 06 | ✓ | ✓ | [Rust] |
| 07 | | | | | 07 | ✓ | ✓ | [Rust] |
| 08 | | | | | 08 | | | |
| 09 | | | | | 09 | | | |
| 10 | | | | | 10 | | | |

6
2022/day-07/Cargo.toml Normal file
View File

@ -0,0 +1,6 @@
[package]
name = "aoc-2022-07"
version = "0.1.0"
edition = "2021"
[dependencies]

5
2022/day-07/Justfile Normal file
View File

@ -0,0 +1,5 @@
@part PART INPUT_FILE="inputs/puzzle.txt":
cargo --quiet run --bin part_{{PART}} -- {{INPUT_FILE}}
clean:
cargo clean

File diff suppressed because it is too large Load Diff

View 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

View File

@ -0,0 +1,17 @@
use std::{env, io};
use aoc_2022_07::{parse_input, path_sizes, DirMap};
fn main() -> io::Result<()> {
let infile_path = env::args().nth(1).expect("input file");
let paths = parse_input(infile_path)?;
let mut sizes = DirMap::new();
path_sizes(&paths, &mut sizes);
let sum: usize = sizes.values().filter(|&&val| val <= 100_000).sum();
println!("{sum:#?}");
Ok(())
}

View File

@ -0,0 +1,29 @@
use std::{env, io};
use aoc_2022_07::{parse_input, path_sizes, DirMap};
const MAX_DISK_SPACE: usize = 70_000_000;
const REQUIRED_SIZE: usize = 30_000_000;
fn main() -> io::Result<()> {
let infile_path = env::args().nth(1).expect("input file");
let paths = parse_input(infile_path)?;
let mut sizes = DirMap::new();
path_sizes(&paths, &mut sizes);
let used_disk_space = *sizes.get("/").unwrap();
let free_disk_space = MAX_DISK_SPACE - used_disk_space;
let req_disk_space = REQUIRED_SIZE - free_disk_space;
let values = sizes
.values()
.filter(|&&v| v >= req_disk_space)
.collect::<Vec<_>>();
let smol = values.iter().min().unwrap();
println!("{smol}");
Ok(())
}

134
2022/day-07/src/lib.rs Normal file
View File

@ -0,0 +1,134 @@
use std::{
collections::HashMap,
fs::File,
io::{self, BufRead, BufReader},
path::Path,
};
#[derive(Debug)]
#[allow(dead_code)]
pub enum Content {
File { size: usize, path: String },
Dir { path: String },
}
enum Command {
ChangeDirectory(String),
List,
}
pub type FileList = Vec<Content>;
pub type DirMap<T = FileList> = HashMap<String, T>;
pub fn parse_input<P>(path: P) -> io::Result<DirMap>
where
P: AsRef<Path>,
{
let file = File::open(path)?;
let reader = BufReader::new(file);
let mut cwd = String::from("");
let mut paths = DirMap::new();
let mut cur_content = FileList::new();
for line in reader.lines() {
let line = line?;
let parts: Vec<&str> = line.split_whitespace().collect();
let cmd = match *parts.first().expect("invalid line") {
"$" => {
if !cur_content.is_empty() {
paths.insert(cwd.clone(), cur_content.drain(..).collect());
}
Some(parse_cmd(&parts[1..]))
}
_ => None,
};
match cmd {
Some(Command::ChangeDirectory(cd_path)) => {
cwd = match (cd_path.as_ref(), cwd.as_ref()) {
("/", "/") => cwd,
("/", _) => "/".into(),
("..", _) => match cwd.rsplit_once("/").unwrap() {
("", _) => "/".into(),
(p, _) => p.into(),
},
(p, "/") => format!("/{p}"),
(p, _) => format!("{cwd}/{p}"),
};
}
Some(Command::List) => (),
_ => {
let content = parse_content_part(&line);
cur_content.push(content);
}
}
}
if !cur_content.is_empty() {
paths.insert(cwd.clone(), cur_content);
}
Ok(paths)
}
pub fn path_sizes(dirs: &DirMap, mut size_map: &mut DirMap<usize>) {
for (path, contents) in dirs {
let size = size_at_path(&path, &contents, &dirs, &mut size_map);
size_map.insert(path.to_owned(), size);
}
}
fn size_at_path(
cur_path: &str,
contents: &[Content],
dirs: &DirMap,
size_map: &mut DirMap<usize>,
) -> usize {
let mut sum = 0;
for content in contents {
sum += match content {
Content::File { size, .. } => *size,
Content::Dir { path } => {
let dir_path = join_paths(cur_path, path);
let dir_content = dirs.get(&dir_path).expect("invalid dir path");
size_at_path(&dir_path, dir_content, dirs, size_map)
}
}
}
sum
}
fn join_paths(a: &str, b: &str) -> String {
match a {
"/" => format!("/{b}"),
_ => format!("{a}/{b}"),
}
}
fn parse_content_part(input: &str) -> Content {
let parts: Vec<_> = input.split_whitespace().collect();
match parts[..] {
["dir", path, ..] => Content::Dir {
path: path.to_owned(),
},
[size, path, ..] => Content::File {
size: size.parse().unwrap(),
path: path.to_owned(),
},
_ => panic!("invalid content"),
}
}
fn parse_cmd(input: &[&str]) -> Command {
match input[..] {
["cd", ch_dir, ..] => Command::ChangeDirectory(ch_dir.to_owned()),
["ls", ..] => Command::List,
_ => panic!("unexpected command line input"),
}
}

View File

@ -9,4 +9,4 @@
- [2019](2019/README.md) (0% completed) - [2019](2019/README.md) (0% completed)
- [2020](2020/README.md) (20% completed) - [2020](2020/README.md) (20% completed)
- [2021](2021/README.md) (68% completed) - [2021](2021/README.md) (68% completed)
- [2022](2022/README.md) (24% completed) - [2022](2022/README.md) (28% completed)