Add solution for 2022 day 07
This commit is contained in:
parent
500d952ee3
commit
2ec8b3934e
4
2022/Cargo.lock
generated
4
2022/Cargo.lock
generated
@ -32,6 +32,10 @@ dependencies = [
|
||||
"itertools",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aoc-2022-07"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.8.0"
|
||||
|
@ -6,6 +6,7 @@ members = [
|
||||
"./day-04",
|
||||
"./day-05",
|
||||
"./day-06",
|
||||
"./day-07",
|
||||
]
|
||||
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
| 04 | ✓ | ✓ | [Rust] |
|
||||
| 05 | ✓ | ✓ | [Rust] |
|
||||
| 06 | ✓ | ✓ | [Rust] |
|
||||
| 07 | | | |
|
||||
| 07 | ✓ | ✓ | [Rust] |
|
||||
| 08 | | | |
|
||||
| 09 | | | |
|
||||
| 10 | | | |
|
||||
|
6
2022/day-07/Cargo.toml
Normal file
6
2022/day-07/Cargo.toml
Normal file
@ -0,0 +1,6 @@
|
||||
[package]
|
||||
name = "aoc-2022-07"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
5
2022/day-07/Justfile
Normal file
5
2022/day-07/Justfile
Normal file
@ -0,0 +1,5 @@
|
||||
@part PART INPUT_FILE="inputs/puzzle.txt":
|
||||
cargo --quiet run --bin part_{{PART}} -- {{INPUT_FILE}}
|
||||
|
||||
clean:
|
||||
cargo clean
|
1052
2022/day-07/inputs/puzzle.txt
Normal file
1052
2022/day-07/inputs/puzzle.txt
Normal file
File diff suppressed because it is too large
Load Diff
23
2022/day-07/inputs/test.txt
Normal file
23
2022/day-07/inputs/test.txt
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
|
17
2022/day-07/src/bin/part_one.rs
Normal file
17
2022/day-07/src/bin/part_one.rs
Normal 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(())
|
||||
}
|
29
2022/day-07/src/bin/part_two.rs
Normal file
29
2022/day-07/src/bin/part_two.rs
Normal 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
134
2022/day-07/src/lib.rs
Normal 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"),
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user