Day 7 done... forgot to commit last night

This commit is contained in:
Daniel Flanagan 2022-12-08 11:27:58 -06:00
parent de796bdb0a
commit 16877f5f1d
Signed by untrusted user: lytedev-divvy
GPG Key ID: 6D69CEEE4ABBCD82
1 changed files with 35 additions and 131 deletions

View File

@ -1,107 +1,61 @@
mod common; mod common;
use std::cell::RefCell; use std::{collections::HashMap, num::Wrapping};
use std::collections::HashMap;
use std::collections::HashSet;
use std::rc::Rc;
#[derive(Debug, Clone)] type Result = Wrapping<usize>;
struct DirTree { type Input = HashMap<String, Result>;
files: HashMap<String, usize>,
subdirectories: HashMap<String, Rc<RefCell<Self>>>,
parent: Option<Rc<RefCell<Self>>>,
}
impl DirTree {
pub fn new(parent: Option<Rc<RefCell<Self>>>) -> Self {
Self {
files: HashMap::new(),
subdirectories: HashMap::new(),
parent,
}
}
pub fn root() -> Self {
Self::new(None)
}
}
type Input = Rc<RefCell<DirTree>>;
type Result = usize;
fn processed_input(input: &str) -> Input { fn processed_input(input: &str) -> Input {
let root = Rc::new(RefCell::new(DirTree::root())); let mut result: Input = HashMap::from([("/".to_string(), Wrapping(0))]);
let mut current_dir = Rc::clone(&root); let mut current_path = vec![];
let vp = |v: &[&str]| format!("/{}", v.join("/"));
for l in input.lines() { for l in input.lines() {
println!("line: {}", l); println!("line: {}", l);
if l == "$ cd /" { if l == "$ cd /" {
current_dir = Rc::clone(&root); println!("cwd '/'");
current_path.clear();
} else if l == "$ ls" { } else if l == "$ ls" {
continue; continue;
} else if l.starts_with("dir ") { } else if l.starts_with("dir ") {
let d = &l[4..]; current_path.push(&l[4..]);
current_dir.borrow_mut().subdirectories.insert( let p = vp(&current_path);
d.to_string(), println!("inserting path '{}'", p);
Rc::new(RefCell::new(DirTree::new(Some(Rc::clone(&current_dir))))), current_path.pop();
); result.insert(p, Wrapping(0));
} else if l.starts_with("$ cd ..") { } else if l.starts_with("$ cd ..") {
let cur = Rc::clone(&current_dir); current_path.pop();
current_dir = Rc::clone(&cur.borrow().parent.as_ref().unwrap()); println!("cwd '{}'", vp(&current_path));
} else if l.starts_with("$ cd ") { } else if l.starts_with("$ cd ") {
let d = &l[5..]; current_path.push(&l[5..]);
let cur = Rc::clone(&current_dir); println!("cwd '{}'", vp(&current_path));
current_dir = Rc::clone(&cur.borrow().subdirectories.get(d).unwrap());
} else { } else {
let mut args = l.split(' '); let size = l.split(' ').next().unwrap().parse::<usize>().unwrap();
let size = args.next().unwrap().parse::<usize>().unwrap(); for i in (0..=current_path.len()).rev() {
current_dir let p = vp(&current_path[0..i]);
.borrow_mut() println!("adding {} to path '{}'", size, p);
.files *(result.get_mut(&p).unwrap()) += size;
.insert(args.next().unwrap().to_string(), size); }
} }
} }
return root;
return result;
} }
const PART1_LIMIT: usize = 100_000; const PART1_LIMIT: usize = 100_000;
fn dfs1(input: Input, path: String) -> usize {
let dt = input.borrow();
let files_size = dt.files.values().map(|r| r.to_owned()).sum::<usize>();
let subdir_sizes: Vec<usize> = dt
.subdirectories
.iter()
.map(|(p, sdt)| dfs1(sdt.clone(), format!("{}/{}", path, p)))
.collect();
let subdirs_size = subdir_sizes.iter().sum::<usize>();
let this_dir_size = subdirs_size + files_size;
let counted = subdir_sizes.iter().filter(|s| **s < PART1_LIMIT).sum();
println!(
"path: {}, files: {:?}, files_size: {}, subdirs_size: {}, counted: {}",
path, dt.files, files_size, subdirs_size, counted
);
let mut r = counted;
if this_dir_size < PART1_LIMIT {
r = counted + this_dir_size;
}
println!(
"return {}, {}",
counted + this_dir_size,
"hy" // std::backtrace::Backtrace::capture()
);
return r;
}
fn part1(input: &Input) -> Result { fn part1(input: &Input) -> Result {
dfs1(input.clone(), "".to_string()) let lim = Wrapping(PART1_LIMIT);
input.values().filter(|s| **s < lim).sum()
} }
fn part2(input: &Input) -> Result { fn part2(input: &Input) -> Result {
0 let to_free = input.get("/").unwrap() - Wrapping(40_000_000);
*input
.values()
.min_by(|a, b| (**a - to_free).cmp(&(**b - to_free)))
.unwrap()
} }
fn main() { fn main() {
@ -109,13 +63,8 @@ fn main() {
eprintln!("{}\n\nAbove is your input file.\n\n", input_text); eprintln!("{}\n\nAbove is your input file.\n\n", input_text);
let input = processed_input(&input_text); let input = processed_input(&input_text);
common::show_answers(&part1(&input), &part2(&input)) common::show_answers(&part1(&input), &part2(&input))
// common::show_both_answers(&both_parts(&input))
} }
// fn both_parts(input: &Input) -> (Result, Result) {
// (0, 0)
// }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -147,52 +96,7 @@ $ ls
#[test] #[test]
fn test() { fn test() {
let input = processed_input(TEST_INPUT); let input = processed_input(TEST_INPUT);
assert_eq!(part1(&input), 95437); assert_eq!(part1(&input), Wrapping(95437));
assert_eq!(part2(&input), 0); assert_eq!(part2(&input), Wrapping(24933642));
// assert_eq!(both_parts(&input), (0, 0));
}
const TEST_INPUT2: &str = "$ cd /
$ ls
dir a
100 x.txt
$ cd a
$ ls
dir b
100 y.txt
$ cd b
$ ls
100 z.txt";
const TEST_INPUT3: &str = "$ cd /
$ ls
dir a
100 x.txt
$ cd a
$ ls
dir b
100 y.txt
$ cd b
$ ls
dir c
100 z.txt
$ cd c
$ ls
100 zz.txt";
// $ cd a
// $ ls
// dir a
// 100 c.txt
// $ cd a
// $ ls
// 100 d.txt
// ";
#[test]
fn test2() {
let input = processed_input(TEST_INPUT2);
assert_eq!(part1(&input), 600);
let input3 = processed_input(TEST_INPUT2);
assert_eq!(part1(&input), 1000);
// assert_eq!(both_parts(&input), (0, 0));
} }
} }