Cleanup for 2022 day 7: Turned into a lib and introduced parse errors

This commit is contained in:
Burnus 2023-05-14 13:52:47 +02:00
parent c61f28a057
commit d3d1566086
2 changed files with 39 additions and 26 deletions

View file

@ -1,4 +1,17 @@
use std::fs; use core::fmt::Display;
#[derive(Debug, PartialEq, Eq)]
pub enum ParseError {
LineMalformed(String),
}
impl Display for ParseError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::LineMalformed(v) => write!(f, "Line is malformed: {v}"),
}
}
}
struct FileSystem { struct FileSystem {
nodes: Vec<Node>, nodes: Vec<Node>,
@ -78,7 +91,7 @@ impl FileSystem {
self.nodes[cwd].last_child = Some(NodeID { index: new_node }); self.nodes[cwd].last_child = Some(NodeID { index: new_node });
} }
fn parse_terminal_output(&mut self, terminal_output: &str) { fn parse_terminal_output(&mut self, terminal_output: &str) -> Result<(), ParseError> {
for line in terminal_output.lines() { for line in terminal_output.lines() {
if line.starts_with("$ cd") { if line.starts_with("$ cd") {
self.cd(&line[5..]); self.cd(&line[5..]);
@ -86,8 +99,11 @@ impl FileSystem {
continue; continue;
} else if let Some((size, name)) = line.split_once(' ') { } else if let Some((size, name)) = line.split_once(' ') {
self.ensure_child_exists(name, size.parse().ok()); self.ensure_child_exists(name, size.parse().ok());
} else {
return Err(ParseError::LineMalformed(line.to_string()));
} }
} }
Ok(())
} }
fn get_directory_sizes(&self, anchor: NodeID) -> Vec<(String, usize)> { fn get_directory_sizes(&self, anchor: NodeID) -> Vec<(String, usize)> {
@ -109,18 +125,13 @@ impl FileSystem {
} }
} }
fn read_file(path: &str) -> String { pub fn run(terminal_output: &str) -> Result<(usize, usize), ParseError> {
fs::read_to_string(path)
.expect("File not Found")
}
fn analyze_filesystem(terminal_output: &str) -> (usize, usize) {
let mut file_system = FileSystem { let mut file_system = FileSystem {
nodes: Vec::new(), nodes: Vec::new(),
current_working_dir: NodeID { index: 0 }, current_working_dir: NodeID { index: 0 },
}; };
file_system.init(); file_system.init();
file_system.parse_terminal_output(terminal_output); file_system.parse_terminal_output(terminal_output)?;
let directory_sizes = file_system.get_directory_sizes(NodeID { index: 0 }); let directory_sizes = file_system.get_directory_sizes(NodeID { index: 0 });
let dir_sizes_under_100k_sum: usize = directory_sizes.iter() let dir_sizes_under_100k_sum: usize = directory_sizes.iter()
@ -132,27 +143,29 @@ fn analyze_filesystem(terminal_output: &str) -> (usize, usize) {
.filter(|(_, size)| *size>=total_size-40_000_000) .filter(|(_, size)| *size>=total_size-40_000_000)
.map(|(_, size)| *size) .map(|(_, size)| *size)
.min() .min()
.unwrap(); .unwrap_or_default();
(dir_sizes_under_100k_sum, smallest_dir_to_delete_size) Ok((dir_sizes_under_100k_sum, smallest_dir_to_delete_size))
} }
fn main() { #[cfg(test)]
let terminal_output = read_file("input"); mod tests {
use super::*;
use std::fs::read_to_string;
let (dir_sizes_under_100k_sum, smallest_dir_to_delete_size) = analyze_filesystem(&terminal_output); fn read_file(name: &str) -> String {
println!("There are {} Bytes in directories of at most 100 kB total size.", dir_sizes_under_100k_sum); read_to_string(name).expect(&format!("Unable to read file: {name}")[..]).trim().to_string()
println!("The smallest dir that would free up enough space has {} Bytes", smallest_dir_to_delete_size); }
}
#[test] #[test]
fn sample_input() { fn test_sample() {
let terminal_output = read_file("tests/sample_input"); let sample_input = read_file("tests/sample_input");
assert_eq!(analyze_filesystem(&terminal_output), (95437, 24933642)); assert_eq!(run(&sample_input), Ok((95437, 24933642)));
} }
#[test] #[test]
fn challenge_input() { fn test_challenge() {
let terminal_output = read_file("tests/input"); let challenge_input = read_file("tests/challenge_input");
assert_eq!(analyze_filesystem(&terminal_output), (1743217, 8319096)); assert_eq!(run(&challenge_input), Ok((1743217, 8319096)));
}
} }