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