Compare commits
2 Commits
5e4e024fcb
...
30edbeb9b9
| Author | SHA1 | Date | |
|---|---|---|---|
| 30edbeb9b9 | |||
| 67fc0bbcb5 |
1096
inputs/day7.txt
Normal file
1096
inputs/day7.txt
Normal file
File diff suppressed because it is too large
Load Diff
8
src/bin/day07_1.rs
Normal file
8
src/bin/day07_1.rs
Normal file
@@ -0,0 +1,8 @@
|
||||
use std::fs;
|
||||
|
||||
use aoc2022::day07::process_part_1;
|
||||
|
||||
fn main() {
|
||||
let file = fs::read_to_string("./inputs/day7.txt").unwrap();
|
||||
println!("{}", process_part_1(&file));
|
||||
}
|
||||
8
src/bin/day07_2.rs
Normal file
8
src/bin/day07_2.rs
Normal file
@@ -0,0 +1,8 @@
|
||||
use std::fs;
|
||||
|
||||
use aoc2022::day07::process_part_2;
|
||||
|
||||
fn main() {
|
||||
let file = fs::read_to_string("./inputs/day7.txt").unwrap();
|
||||
println!("{}", process_part_2(&file));
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
use itertools::Itertools;
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
pub fn process_part_1(input: &str) -> usize {
|
||||
find_unique_window_start(input, 4)
|
||||
@@ -14,7 +14,7 @@ pub fn find_unique_window_start(input: &str, window_size: usize) -> usize {
|
||||
.chars()
|
||||
.collect::<Vec<_>>()
|
||||
.windows(window_size)
|
||||
.take_while(|x| x.iter().unique().count() != x.len())
|
||||
.take_while(|x| x.iter().collect::<BTreeSet<_>>().len() != x.len())
|
||||
.count()
|
||||
}
|
||||
|
||||
|
||||
158
src/day07.rs
Normal file
158
src/day07.rs
Normal file
@@ -0,0 +1,158 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::{tag, take_till1};
|
||||
use nom::character::complete::{newline, space1};
|
||||
use nom::character::{complete, is_newline};
|
||||
use nom::multi::separated_list1;
|
||||
use nom::IResult;
|
||||
|
||||
pub fn process_part_1(input: &str) -> u32 {
|
||||
let (_, commands) = parse_commands(input).unwrap();
|
||||
let directories = build_directory_tree_from_commands(commands);
|
||||
|
||||
directories.values().filter(|size| **size <= 100_000).sum()
|
||||
}
|
||||
|
||||
pub fn process_part_2(input: &str) -> u32 {
|
||||
let (_, commands) = parse_commands(input).unwrap();
|
||||
let directories = build_directory_tree_from_commands(commands);
|
||||
|
||||
let total_space = 70_000_000;
|
||||
let required_space = 30_000_000;
|
||||
let current_space = total_space - *directories.get("").unwrap();
|
||||
let wanted_space = required_space - current_space;
|
||||
|
||||
directories
|
||||
.values()
|
||||
.filter(|size| **size >= wanted_space)
|
||||
.map(|size| *size)
|
||||
.min()
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
fn build_directory_tree_from_commands(commands: Vec<Command>) -> BTreeMap<String, u32> {
|
||||
let mut cwd: Vec<&str> = vec![];
|
||||
let mut directories: BTreeMap<String, u32> = BTreeMap::new();
|
||||
for command in commands {
|
||||
match command {
|
||||
Command::Cd("/") => {
|
||||
cwd = vec![];
|
||||
}
|
||||
Command::Cd("..") => {
|
||||
cwd.pop();
|
||||
}
|
||||
Command::Cd(name) => {
|
||||
cwd.push(name);
|
||||
}
|
||||
Command::Ls(files) => {
|
||||
for file in files {
|
||||
match file {
|
||||
DirEntry::File { name: _name, size } => {
|
||||
for i in 0..=cwd.len() {
|
||||
directories
|
||||
.entry(cwd[..i].join("/"))
|
||||
.and_modify(|f| *f += size)
|
||||
.or_insert(size);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
directories
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Command<'a> {
|
||||
Cd(&'a str),
|
||||
Ls(Vec<DirEntry<'a>>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum DirEntry<'a> {
|
||||
Dir(&'a str),
|
||||
File { name: &'a str, size: u32 },
|
||||
}
|
||||
|
||||
fn parse_commands(input: &str) -> IResult<&str, Vec<Command>> {
|
||||
separated_list1(newline, parse_command)(input)
|
||||
}
|
||||
|
||||
fn parse_command(input: &str) -> IResult<&str, Command> {
|
||||
let (input, _) = tag("$ ")(input)?;
|
||||
alt((parse_cd, parse_ls))(input)
|
||||
}
|
||||
|
||||
fn parse_cd(input: &str) -> IResult<&str, Command> {
|
||||
let (input, _) = tag("cd")(input)?;
|
||||
let (input, _) = space1(input)?;
|
||||
let (input, arg) = parse_file_name(input)?;
|
||||
Ok((input, Command::Cd(arg)))
|
||||
}
|
||||
|
||||
fn parse_ls(input: &str) -> IResult<&str, Command> {
|
||||
let (input, _) = tag("ls")(input)?;
|
||||
let (input, _) = newline(input)?;
|
||||
let (input, entries) =
|
||||
separated_list1(tag("\n"), alt((parse_dir_entry_dir, parse_dir_entry_file)))(input)?;
|
||||
Ok((input, Command::Ls(entries)))
|
||||
}
|
||||
|
||||
fn parse_dir_entry_dir(input: &str) -> IResult<&str, DirEntry> {
|
||||
let (input, _) = tag("dir ")(input)?;
|
||||
let (input, name) = parse_file_name(input)?;
|
||||
Ok((input, DirEntry::Dir(name)))
|
||||
}
|
||||
|
||||
fn parse_dir_entry_file(input: &str) -> IResult<&str, DirEntry> {
|
||||
let (input, size) = complete::u32(input)?;
|
||||
let (input, _) = tag(" ")(input)?;
|
||||
let (input, name) = parse_file_name(input)?;
|
||||
Ok((input, DirEntry::File { name, size }))
|
||||
}
|
||||
|
||||
fn parse_file_name(input: &str) -> IResult<&str, &str> {
|
||||
take_till1(|c| is_newline(c as u8))(input)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
const INPUT: &str = "$ 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";
|
||||
|
||||
#[test]
|
||||
fn day1() {
|
||||
assert_eq!(process_part_1(INPUT), 95437);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn day2() {
|
||||
assert_eq!(process_part_2(INPUT), 24933642);
|
||||
}
|
||||
}
|
||||
@@ -7,3 +7,4 @@ pub mod day03;
|
||||
pub mod day04;
|
||||
pub mod day05;
|
||||
pub mod day06;
|
||||
pub mod day07;
|
||||
|
||||
Reference in New Issue
Block a user