Complete day 7 part 1
This commit is contained in:
parent
34a7dd17fa
commit
7a0ee1c45e
178
day7/src/main.rs
178
day7/src/main.rs
@ -9,11 +9,9 @@ struct File {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl File {
|
impl File {
|
||||||
fn new<T: ToString + ?Sized>(raw_line: &T) -> Self {
|
fn new<T: ToString + ?Sized>(size: &T, name: &T) -> Self {
|
||||||
let raw = raw_line.to_string();
|
let size = size.to_string().parse::<u128>().unwrap();
|
||||||
let parts: Vec<&str> = raw.split(' ').collect();
|
let name = name.to_string();
|
||||||
let size = parts[0].parse::<u128>().unwrap();
|
|
||||||
let name = parts[1].to_string();
|
|
||||||
|
|
||||||
File { name, size }
|
File { name, size }
|
||||||
}
|
}
|
||||||
@ -26,7 +24,7 @@ struct Dir {
|
|||||||
parent: String,
|
parent: String,
|
||||||
name: String,
|
name: String,
|
||||||
files: Vec<File>,
|
files: Vec<File>,
|
||||||
dirs: Vec<String>,
|
subdirs: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Dir {
|
impl Dir {
|
||||||
@ -35,21 +33,58 @@ impl Dir {
|
|||||||
parent: parent.to_string(),
|
parent: parent.to_string(),
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
files: Vec::new(),
|
files: Vec::new(),
|
||||||
dirs: Vec::new(),
|
subdirs: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_file(&mut self, file: File) {
|
||||||
|
self.files.push(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_subdir(&mut self, path: String) {
|
||||||
|
self.subdirs.push(path);
|
||||||
|
}
|
||||||
|
|
||||||
fn get_loose_files_size(&self) -> u128 {
|
fn get_loose_files_size(&self) -> u128 {
|
||||||
self.files
|
self.files
|
||||||
.iter()
|
.iter()
|
||||||
.map(|file| file.size)
|
.map(|file| file.size)
|
||||||
.reduce(|accum, item| accum + item)
|
.reduce(|accum, item| accum + item)
|
||||||
.unwrap()
|
.unwrap_or(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum LineType {
|
||||||
|
Cd(String),
|
||||||
|
Ls,
|
||||||
|
Dir(String),
|
||||||
|
FileAndSize(String, String),
|
||||||
|
}
|
||||||
|
|
||||||
|
use LineType::*;
|
||||||
|
|
||||||
|
impl LineType {
|
||||||
|
fn from(line: &str) -> LineType {
|
||||||
|
let parts: Vec<&str> = line.split_ascii_whitespace().collect();
|
||||||
|
|
||||||
|
match parts[0] {
|
||||||
|
"$" => match parts[1] {
|
||||||
|
"cd" => Cd(parts[2].to_string()),
|
||||||
|
"ls" => Ls,
|
||||||
|
_ => panic!("Invalid command"),
|
||||||
|
},
|
||||||
|
"dir" => Dir(parts[1].to_string()),
|
||||||
|
_ => FileAndSize(parts[0].to_string(), parts[1].to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
struct DirMap {
|
struct DirMap {
|
||||||
current_path: String,
|
current_path: String,
|
||||||
map: HashMap<String, Dir>,
|
map: HashMap<String, Dir>,
|
||||||
@ -57,16 +92,135 @@ struct DirMap {
|
|||||||
|
|
||||||
impl DirMap {
|
impl DirMap {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
DirMap {
|
let current_path = "/".to_string();
|
||||||
current_path: "/".to_string(),
|
let mut map: HashMap<String, Dir> = HashMap::new();
|
||||||
map: HashMap::new(),
|
map.insert(current_path.clone(), Dir::new("", ""));
|
||||||
|
|
||||||
|
DirMap { current_path, map }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cd<T: ToString + ?Sized>(&mut self, new_dir: &T) {
|
||||||
|
let current_path = self.current_path.clone();
|
||||||
|
let new = new_dir.to_string();
|
||||||
|
|
||||||
|
match new.as_str() {
|
||||||
|
"/" => {
|
||||||
|
self.current_path = new.to_string();
|
||||||
|
}
|
||||||
|
".." => {
|
||||||
|
let mut dir_parts: Vec<&str> = current_path.split('/').collect();
|
||||||
|
let _ = dir_parts.pop();
|
||||||
|
self.current_path = dir_parts.join("/");
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.current_path.push('/');
|
||||||
|
self.current_path.push_str(&new);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dir<T: ToString + ?Sized>(&mut self, dir: &T) {
|
||||||
|
let parent = self.current_path.clone();
|
||||||
|
let name = dir.to_string();
|
||||||
|
|
||||||
|
let mut full_path = parent.clone();
|
||||||
|
full_path.push('/');
|
||||||
|
full_path.push_str(&name);
|
||||||
|
|
||||||
|
// Add the new Dir to the path map
|
||||||
|
if !self.map.contains_key(&full_path) {
|
||||||
|
self.map.insert(full_path.clone(), Dir::new(&parent, &name));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the new Dir to the list of subdirectories to the Dir mapped to the current path
|
||||||
|
self.map
|
||||||
|
.get_mut(&self.current_path)
|
||||||
|
.expect(&format!(
|
||||||
|
"This dir ({}) should already exist",
|
||||||
|
&self.current_path
|
||||||
|
))
|
||||||
|
.add_subdir(full_path.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse(&mut self, item: LineType) {
|
||||||
|
match item {
|
||||||
|
Cd(s) => self.cd(&s),
|
||||||
|
Ls => {}
|
||||||
|
Dir(s) => self.dir(&s),
|
||||||
|
FileAndSize(size, name) => {
|
||||||
|
self.map
|
||||||
|
.get_mut(&self.current_path)
|
||||||
|
.expect(&format!(
|
||||||
|
"This dir ({}) should already exist",
|
||||||
|
&self.current_path
|
||||||
|
))
|
||||||
|
.add_file(File::new(&size, &name));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
fn get_path_size_map(dir_map: &DirMap) -> HashMap<String, u128> {
|
||||||
|
let mut size_map: HashMap<String, u128> = HashMap::new();
|
||||||
|
|
||||||
|
// Get the sizes of the leaf node directories
|
||||||
|
dir_map
|
||||||
|
.map
|
||||||
|
.iter()
|
||||||
|
.filter(|(_, v)| v.subdirs.len() == 0)
|
||||||
|
.for_each(|(k, v)| {
|
||||||
|
size_map.insert(k.to_string(), v.get_loose_files_size());
|
||||||
|
});
|
||||||
|
|
||||||
|
// Calculate dir sizes by the length of the path from largest to smallest,
|
||||||
|
// so we can start with the lowest branches of the tree when calculating folder sizes
|
||||||
|
let mut branch_paths: Vec<&String> = dir_map
|
||||||
|
.map
|
||||||
|
.iter()
|
||||||
|
.filter(|(_, v)| v.subdirs.len() > 0)
|
||||||
|
.map(|(k, _)| k)
|
||||||
|
.collect();
|
||||||
|
branch_paths.sort();
|
||||||
|
branch_paths.reverse();
|
||||||
|
|
||||||
|
branch_paths.into_iter().for_each(|path| {
|
||||||
|
let dir = dir_map.map.get(path).unwrap();
|
||||||
|
|
||||||
|
let base_size = dir.get_loose_files_size();
|
||||||
|
let subdir_size: u128 = dir
|
||||||
|
.subdirs
|
||||||
|
.iter()
|
||||||
|
.map(|sub| {
|
||||||
|
*size_map
|
||||||
|
.get(sub)
|
||||||
|
.expect("Dir {} should already have had its size calculated")
|
||||||
|
})
|
||||||
|
.reduce(|accum, item| accum + item)
|
||||||
|
.unwrap_or(0);
|
||||||
|
|
||||||
|
size_map.insert(path.to_string(), base_size + subdir_size);
|
||||||
|
});
|
||||||
|
|
||||||
|
size_map
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let file_str = include_str!("input.txt");
|
let file_str = include_str!("input.txt");
|
||||||
let path_map = DirMap::new();
|
let mut path_map = DirMap::new();
|
||||||
|
|
||||||
|
file_str
|
||||||
|
.lines()
|
||||||
|
.map(|line| LineType::from(line))
|
||||||
|
.for_each(|cmd| path_map.parse(cmd));
|
||||||
|
|
||||||
|
let size_map = get_path_size_map(&path_map);
|
||||||
|
|
||||||
|
let size_sum = size_map
|
||||||
|
.iter()
|
||||||
|
.filter(|(_, v)| **v < MAX_DIR_SIZE)
|
||||||
|
.fold(0u128, |acc, (_, v)| acc + *v);
|
||||||
|
|
||||||
|
println!("Part 1: Sum of dirs 100K or smaller {:#?}", size_sum);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user