From 1ae3445e12581e65cdc486763ca625f766a4a709 Mon Sep 17 00:00:00 2001 From: Mads Jensen Date: Wed, 17 Jul 2024 10:17:59 +0200 Subject: [PATCH] day9 done --- lib/oasis/src/lib.rs | 68 +++++++++++++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 20 deletions(-) diff --git a/lib/oasis/src/lib.rs b/lib/oasis/src/lib.rs index 63fa9f7..2260245 100644 --- a/lib/oasis/src/lib.rs +++ b/lib/oasis/src/lib.rs @@ -1,8 +1,13 @@ use std::{num::ParseIntError, str::FromStr}; +/// Errors than can occur during an Oasis report #[derive(Debug)] pub enum OasisError { + /// Failed to parse History ParseHistory(ParseIntError), + + /// No histories found when parsing + NoHistories, } impl From for OasisError { @@ -11,58 +16,58 @@ impl From for OasisError { } } +/// A value from an Oasis report pub type Value = i64; +/// A Layer in a History #[derive(Debug, Clone)] pub struct Layer(Vec); impl Layer { - #[inline(always)] + /// Checks if all values in the layer is `0` fn is_all_zero(&self) -> bool { self.0.iter().all(|n| *n == 0) } - #[inline(always)] + /// Calculates the differences between values in the layer, to create the layer below it. pub fn get_next_layer(&self) -> Option { if self.is_all_zero() { return None; } + // Get differences let next = self.0.windows(2).map(|a| a[1] - a[0]).collect(); Some(Self(next)) } - #[inline(always)] + /// Returns the last value of the layer, if any pub fn last_value(&self) -> Option<&Value> { self.0.last() } - #[inline(always)] + /// Returns the first value of the layer, if any pub fn first_value(&self) -> Option<&Value> { self.0.first() } } +/// A History #[derive(Debug)] -pub struct History(Layer); +pub struct History(Vec); impl FromStr for History { type Err = OasisError; fn from_str(s: &str) -> Result { - Ok(Self(Layer( + // Create a vector, containing the first layer + let mut layers = vec![Layer( s.split_whitespace() .map(|x| x.parse::()) .collect::>()?, - ))) - } -} - -impl History { - fn get_layers(&self) -> Vec { - let mut layers = vec![self.0.clone()]; + )]; + // Calculate the rest of the layers loop { let Some(current) = layers.last() else { unreachable!("Always at least one layer!") @@ -75,42 +80,59 @@ impl History { } } - layers + Ok(Self(layers)) } +} +impl History { + /// Calculates the next value in the history pub fn calculate_next_value(&self) -> Value { - self.get_layers() + self.0 .iter() .rev() .fold(0, |acc, layer| layer.last_value().map_or(acc, |value| acc + value)) } + /// Calculates the previous value in the history pub fn calculate_prev_value(&self) -> Value { - self.get_layers() - .iter() - .rev() - .fold(0, |acc, layer| layer.first_value().map_or(acc, |value| acc + value)) + self.0.iter().rev().fold(0, |below, layer| { + layer.first_value().map_or(below, |value| value - below) + }) } } +/// An Oasis-Report #[derive(Debug)] pub struct Report(Vec); impl Report { + /// Returns the sum of all the next values in the Reports Histories pub fn get_next_values_sum(&self) -> Value { self.0.iter().map(|history| history.calculate_next_value()).sum() } + /// Returns the sum of all the previous values in the Reports Histories pub fn get_prev_values_sum(&self) -> Value { self.0.iter().map(|history| history.calculate_prev_value()).sum() } + + /// Checks if the report is empty (No histories) + fn is_empty(&self) -> bool { + self.0.is_empty() + } } impl FromStr for Report { type Err = OasisError; fn from_str(s: &str) -> Result { - Ok(Self(s.lines().map(History::from_str).collect::>()?)) + let report = Self(s.lines().map(History::from_str).collect::>()?); + + if report.is_empty() { + return Err(OasisError::NoHistories); + } + + Ok(report) } } @@ -139,6 +161,12 @@ mod tests { assert_eq!(sum, -2); } + #[test] + #[should_panic] + fn empty_test() { + Report::from_str("").expect("Failed to parse"); + } + #[test] fn solution_1() { let report = Report::from_str(EXAMPLE_1).expect("Failed to parse");