1
0
Fork 0

day 7 solution

main
Andrew Coleman 2022-12-07 14:08:12 -05:00
parent 55ab9faaba
commit ce63f9771b
5 changed files with 1241 additions and 12 deletions

1014
2022/day7.txt Normal file

File diff suppressed because it is too large Load Diff

177
2022/src/days/day7.rs Normal file
View File

@ -0,0 +1,177 @@
use anyhow::{anyhow, Result};
use std::fs;
use std::collections::BTreeMap;
#[derive(Debug,Default)]
struct Dir {
name: String,
files: Vec<File>,
directories: Vec<Dir>,
total_size: usize,
}
#[derive(Debug)]
struct File {
name: String,
size: usize,
}
fn dig_directory<'a, 'b>(dirname: &'b String, fs: &'a mut Dir) -> Option<&'a mut Dir> {
if dirname == "/" && fs.name == *dirname {
return Some(fs);
}
for entry in fs.directories.iter_mut() {
if entry.name == *dirname {
return Some(entry);
} else if dirname.starts_with(&entry.name) {
return dig_directory(dirname, entry);
}
}
None
}
fn just_sizes<'a>(dir: &'a mut Dir) -> usize {
let mut size: usize = 0;
for file in dir.files.iter() {
size += file.size;
}
for subdir in dir.directories.iter_mut() {
size += just_sizes(subdir);
}
dir.total_size = size;
size
}
fn part_one_sizes<'a>(dir: &'a Dir) -> usize {
let mut size: usize = 0;
if dir.total_size > 100000 {
size = 0
} else {
size += dir.total_size;
}
for subdir in dir.directories.iter() {
size += part_one_sizes(subdir);
}
size
}
fn part_two_sizes<'a>(dir: &'a Dir, needed: u32) -> Option<(u32, &'a str)> {
let mut map: BTreeMap<u32, &'a str> = BTreeMap::new();
part_two_recurse(&mut map, dir);
for (key, val) in map.iter() {
if *key >= needed {
return Some((*key, val))
}
}
None
}
fn part_two_recurse<'a>(map: &mut BTreeMap<u32, &'a str>, dir: &'a Dir) {
map.insert((dir.total_size as u32).try_into().unwrap(), dir.name.as_str());
for subdir in dir.directories.iter() {
part_two_recurse(map, subdir);
}
}
pub fn run() -> Result<()> {
let file_contents = fs::read_to_string("day7.txt")?;
//let file_contents = fs::read_to_string("tests/day7.txt")?;
let mut root = Dir {
name: String::from("/"),
..Default::default()
};
let mut current_path: Vec<&str> = Vec::with_capacity(25);
let mut current = &mut root;
for line in file_contents.lines() {
if &line[0..1] == "$" {
let cmd = &line[2..4];
match cmd {
"ls" => {
continue;
}
"cd" => {
let dirname = &line[5..];
current = &mut root;
if dirname == ".." {
current_path.pop().expect("going past root");
let newdir = format!("/{}", current_path.join("/"));
current = dig_directory(&newdir, current).expect("missing .. dir");
} else if dirname == "/" {
current_path.clear();
} else {
current_path.push(dirname);
let newdir = format!("/{}", current_path.join("/"));
current = dig_directory(&newdir, current).expect("missing subdir");
}
continue;
}
_ => {
return Err(anyhow!("unknown command {}", line));
}
}
} else if line.chars().next().unwrap().is_numeric() {
let mut fields = line.split_whitespace();
let size: usize = fields
.next()
.expect("missing file size")
.parse()
.expect("invalid file size");
let name = fields.next().expect("missing file name");
current_path.push(name);
let new_filename = format!("/{}", current_path.join("/"));
current_path.pop();
if let None = current.files.iter().find(|x| x.name == new_filename) {
current.files.push(File {
name: new_filename,
size: size,
});
}
} else if line.starts_with("dir") {
let current_dirname = &line[4..];
current_path.push(current_dirname);
let new_dirname = format!("/{}", current_path.join("/"));
current_path.pop();
if let None = current.directories.iter().find(|x| x.name == new_dirname) {
let dir = Dir {
name: new_dirname,
..Default::default()
};
current.directories.push(dir);
}
} else {
return Err(anyhow!("malformed line {}", line));
}
}
just_sizes(&mut root);
println!("part one {}", part_one_sizes(&root));
let total_disk = 70000000;
let min_free_space = 30000000;
let free_space = total_disk - root.total_size as u32;
let needed_space = min_free_space - free_space;
println!("total size used {} free {} needed {}", root.total_size, free_space, needed_space);
if let Some((rm_space, rm_name)) = part_two_sizes(&root, needed_space) {
println!("part two: should delete {} to reclaim {} total free space {}", rm_name, rm_space, free_space + rm_space);
} else {
println!("could not find part 2");
}
Ok(())
}

View File

@ -4,3 +4,4 @@ pub mod day3;
pub mod day4;
pub mod day5;
pub mod day6;
pub mod day7;

View File

@ -4,7 +4,10 @@ use std::env;
mod days;
fn help() {
println!("Usage: {} <day-number>", env!("CARGO_BIN_NAME"));
println!(
"Usage: {} day-number <day-number>...",
env!("CARGO_BIN_NAME")
);
}
fn run_day(number: i32) -> Result<()> {
@ -27,6 +30,9 @@ fn run_day(number: i32) -> Result<()> {
6 => {
days::day6::run()?;
}
7 => {
days::day7::run()?;
}
_ => return Err(anyhow!("Invalid day provided")),
}
Ok(())
@ -36,19 +42,27 @@ fn main() -> Result<()> {
let args: Vec<String> = env::args().collect();
match args.len() {
2 => {
let number: i32 = match args[1].parse() {
Ok(n) => n,
Err(_) => {
help();
return Err(anyhow!("Argument is not an integer"));
}
};
run_day(number)?;
0 => {
help();
return Err(anyhow!("No arguments provided"));
}
1 => {
help();
return Err(anyhow!("Not enough arguments provided"));
}
_ => {
help();
return Err(anyhow!("Invalid arguments provided"));
for val in args[1..].iter() {
let number: i32 = match val.parse() {
Ok(n) => n,
Err(_) => {
help();
return Err(anyhow!("Argument {} is not an integer", val));
}
};
println!("Day {}", number);
run_day(number)?;
println!("");
}
}
}

23
2022/tests/day7.txt Normal file
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