mirror of
https://github.com/bertptrs/adventofcode.git
synced 2025-12-26 13:20:32 +01:00
Implement 2022 day 7
This commit is contained in:
@@ -1,9 +1,144 @@
|
||||
use std::fmt::Debug;
|
||||
|
||||
use anyhow::Context;
|
||||
use anyhow::Result;
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag;
|
||||
use nom::bytes::complete::take_until;
|
||||
use nom::character::complete::newline;
|
||||
use nom::combinator::map;
|
||||
use nom::combinator::opt;
|
||||
use nom::multi::many0;
|
||||
use nom::sequence::delimited;
|
||||
use nom::sequence::preceded;
|
||||
use nom::sequence::separated_pair;
|
||||
use nom::sequence::terminated;
|
||||
use nom::sequence::tuple;
|
||||
use nom::IResult;
|
||||
|
||||
pub fn part1(_input: &[u8]) -> Result<String> {
|
||||
todo!()
|
||||
use crate::common::parse_input;
|
||||
|
||||
type Listing<'a> = Vec<(&'a [u8], ListEntry<'a>)>;
|
||||
type Slicing<'a> = &'a [(&'a [u8], ListEntry<'a>)];
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ListEntry<'a> {
|
||||
File(u32),
|
||||
Dir(Listing<'a>),
|
||||
}
|
||||
|
||||
pub fn part2(_input: &[u8]) -> Result<String> {
|
||||
todo!()
|
||||
fn parse_dir(input: &[u8]) -> IResult<&[u8], Listing> {
|
||||
use nom::character::complete::u32;
|
||||
|
||||
let (mut input, mut entries) = preceded(
|
||||
tag("$ ls\n"),
|
||||
many0(
|
||||
// Map many newline-terminated entries
|
||||
terminated(
|
||||
// of either
|
||||
alt((
|
||||
// A size followed by a name
|
||||
map(
|
||||
separated_pair(u32, tag(" "), take_until("\n")),
|
||||
|(size, name)| (name, ListEntry::File(size)),
|
||||
),
|
||||
// Or the word "dir" followed by a name
|
||||
map(preceded(tag("dir "), take_until("\n")), |name| {
|
||||
(name, ListEntry::Dir(Vec::new()))
|
||||
}),
|
||||
)),
|
||||
newline,
|
||||
),
|
||||
),
|
||||
)(input)?;
|
||||
|
||||
// Assumption: directory entries are queried in the order they are listed
|
||||
//
|
||||
// This assumption appears to hold for my input so it's fine
|
||||
for (name, entry) in &mut entries {
|
||||
if let ListEntry::Dir(placeholder) = entry {
|
||||
let (new_input, contents) = delimited(
|
||||
tuple((tag("$ cd "), tag(*name), newline)),
|
||||
parse_dir,
|
||||
// Optional cd'ing out because the last directory is never exited.
|
||||
opt(tag("$ cd ..\n")),
|
||||
)(input)?;
|
||||
|
||||
input = new_input;
|
||||
*placeholder = contents;
|
||||
}
|
||||
}
|
||||
|
||||
Ok((input, entries))
|
||||
}
|
||||
|
||||
fn parse_program(input: &[u8]) -> IResult<&[u8], Listing> {
|
||||
preceded(tag("$ cd /\n"), parse_dir)(input)
|
||||
}
|
||||
|
||||
fn sum_sizes(listing: Slicing<'_>, acc: &mut impl FnMut(u32)) -> u32 {
|
||||
let mut total_size = 0;
|
||||
|
||||
for (_, entry) in listing {
|
||||
match entry {
|
||||
ListEntry::File(size) => total_size += size,
|
||||
ListEntry::Dir(listing) => total_size += sum_sizes(listing, acc),
|
||||
}
|
||||
}
|
||||
|
||||
acc(total_size);
|
||||
|
||||
total_size
|
||||
}
|
||||
|
||||
pub fn part1(input: &[u8]) -> Result<String> {
|
||||
let root = parse_input(input, parse_program)?;
|
||||
|
||||
let mut searched_size = 0;
|
||||
|
||||
sum_sizes(&root, &mut |size| {
|
||||
if size <= 100000 {
|
||||
searched_size += size
|
||||
}
|
||||
});
|
||||
|
||||
Ok(searched_size.to_string())
|
||||
}
|
||||
|
||||
pub fn part2(input: &[u8]) -> Result<String> {
|
||||
const TARGET: u32 = 30000000;
|
||||
const TOTAL: u32 = 70000000;
|
||||
|
||||
let root = parse_input(input, parse_program)?;
|
||||
|
||||
let mut sizes = Vec::new();
|
||||
|
||||
let used = sum_sizes(&root, &mut |size| sizes.push(size));
|
||||
|
||||
let required = TARGET - (TOTAL - used);
|
||||
|
||||
let min = sizes
|
||||
.into_iter()
|
||||
.filter(|&size| size >= required)
|
||||
.min()
|
||||
.context("Did not find dir large enough to delete")?;
|
||||
|
||||
Ok(min.to_string())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
const SAMPLE: &[u8] = include_bytes!("samples/07.txt");
|
||||
|
||||
#[test]
|
||||
fn sample_part1() {
|
||||
assert_eq!(part1(SAMPLE).unwrap(), "95437");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sample_part2() {
|
||||
assert_eq!(part2(SAMPLE).unwrap(), "24933642");
|
||||
}
|
||||
}
|
||||
|
||||
23
2022/src/samples/07.txt
Normal file
23
2022/src/samples/07.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
|
||||
Reference in New Issue
Block a user