diff options
Diffstat (limited to 'src/bin')
-rw-r--r-- | src/bin/day_1.rs | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/src/bin/day_1.rs b/src/bin/day_1.rs new file mode 100644 index 0000000..7c8f104 --- /dev/null +++ b/src/bin/day_1.rs @@ -0,0 +1,97 @@ +use std::io; +use std::io::prelude::*; +use std::iter; +use std::iter::Sum; +use std::num::ParseIntError; +use std::ops::Add; +use std::str::FromStr; + +fn main() { + let stdin = io::stdin(); + + let input = stdin + .lock() + .lines() + .map(|l| l.unwrap().parse::<Module>().unwrap()); + + dbg!(fuel_required(input)); +} + +// TODO: If this were a nice CLI program, it would probably have a switch to choose between these two rather than doing both? +fn fuel_required(it: impl Iterator<Item = Module>) -> (Fuel, Fuel) { + it.map(|m| { + ( + m.fuel_excluding_fuel_weight(), + m.fuel_including_fuel_weight(), + ) + }) + .fold((Fuel(0), Fuel(0)), |(sum_x, sum_y), (x, y)| { + (sum_x + x, sum_y + y) + }) +} + +struct Module { + weight: Weight, +} + +impl FromStr for Module { + type Err = ParseIntError; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + Ok(Module { + weight: Weight(s.parse()?), + }) + } +} + +impl Module { + fn fuel_excluding_fuel_weight(&self) -> Fuel { + self.weight.required_fuel() + } + + fn fuel_including_fuel_weight(&self) -> Fuel { + iter::successors(Some(self.weight.required_fuel()), |fuel| { + if fuel.weight().is_zero() { + None + } else { + Some(fuel.weight().required_fuel()) + } + }) + .sum() + } +} + +struct Weight(u32); + +impl Weight { + fn is_zero(&self) -> bool { + self.0 == 0 + } + + fn required_fuel(&self) -> Fuel { + Fuel((self.0 / 3).saturating_sub(2)) + } +} + +#[derive(Debug)] +struct Fuel(u32); + +impl Fuel { + fn weight(&self) -> Weight { + Weight(self.0) + } +} + +impl Add for Fuel { + type Output = Self; + + fn add(self, other: Self) -> Self { + Fuel(self.0 + other.0) + } +} + +impl Sum for Fuel { + fn sum<I: Iterator<Item = Self>>(iter: I) -> Self { + iter.fold(Fuel(0), Add::add) + } +} |