day 7 solution
parent
55ab9faaba
commit
ce63f9771b
File diff suppressed because it is too large
Load Diff
|
@ -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(())
|
||||
}
|
|
@ -4,3 +4,4 @@ pub mod day3;
|
|||
pub mod day4;
|
||||
pub mod day5;
|
||||
pub mod day6;
|
||||
pub mod day7;
|
||||
|
|
|
@ -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() {
|
||||
0 => {
|
||||
help();
|
||||
return Err(anyhow!("No arguments provided"));
|
||||
}
|
||||
1 => {
|
||||
help();
|
||||
return Err(anyhow!("Not enough 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"));
|
||||
return Err(anyhow!("Argument {} is not an integer", val));
|
||||
}
|
||||
};
|
||||
println!("Day {}", number);
|
||||
run_day(number)?;
|
||||
println!("");
|
||||
}
|
||||
_ => {
|
||||
help();
|
||||
return Err(anyhow!("Invalid arguments provided"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue