Day 7 done... forgot to commit last night
This commit is contained in:
parent
de796bdb0a
commit
16877f5f1d
|
@ -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(¤t_path);
|
||||||
d.to_string(),
|
println!("inserting path '{}'", p);
|
||||||
Rc::new(RefCell::new(DirTree::new(Some(Rc::clone(¤t_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(¤t_dir);
|
current_path.pop();
|
||||||
current_dir = Rc::clone(&cur.borrow().parent.as_ref().unwrap());
|
println!("cwd '{}'", vp(¤t_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(¤t_dir);
|
println!("cwd '{}'", vp(¤t_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(¤t_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));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue