diff --git a/src/days/d07.rs b/src/days/d07.rs index f8e20e3..531bd25 100644 --- a/src/days/d07.rs +++ b/src/days/d07.rs @@ -2,31 +2,156 @@ use super::{Answer, Day, DayImpl}; const CURRENT_DAY: u8 = 7; -type Data = Vec; +#[derive(Debug, Clone, Copy)] +enum Operator { + Add, + Multiply, +} + +impl Operator { + fn calculate(&self, a: u64, b: u64) -> u64 { + match self { + Operator::Multiply => a * b, + Operator::Add => a + b, + } + } +} + +#[derive(Debug, Clone)] +struct CombinationIterator<'a, T> +where + T: Sized + Clone, +{ + iteration: usize, + length: u32, + possibilities: &'a [T], +} + +impl<'a, T> CombinationIterator<'a, T> +where + T: Sized + Clone, +{ + fn get_index_on_position(&self, position: u32) -> usize { + (if position == 0 { + self.iteration + } else { + self.iteration / (self.possibilities.len().pow(position)) + }) % self.possibilities.len() + } + + fn new(possibilities: &'a [T], length: u32) -> Self { + Self { + iteration: 0, + length, + possibilities, + } + } +} + +impl<'a, T> Iterator for CombinationIterator<'a, T> +where + T: Sized + Clone, +{ + type Item = Vec; + + fn next(&mut self) -> Option { + if self.get_index_on_position(self.length) != 0 { + return None; + } + + let values = (0..self.length) + .map(|p| self.possibilities[self.get_index_on_position(p)].clone()) + .collect(); + self.iteration += 1; + return Some(values); + } +} + +#[derive(Debug, Clone)] +pub struct CalibrationEquation { + pub result: u64, + pub parts: Vec, +} + +impl CalibrationEquation { + fn calculate(&self, operations: Vec) -> u64 { + let mut value = self.parts[0]; + + for i in 1..(self.parts.len()) { + value = operations[i - 1].calculate(value, self.parts[i]); + } + + value + } + + fn can_be_valid(&self) -> bool { + CombinationIterator::new( + &[Operator::Add, Operator::Multiply], + (self.parts.len() - 1) as u32, + ) + .map(|o| self.calculate(o)) + .collect::>() + .contains(&self.result) + } +} + +impl From<&str> for CalibrationEquation { + fn from(value: &str) -> Self { + let (first, second) = value.split_once(':').unwrap(); + + Self { + result: first.parse().unwrap(), + parts: second + .trim() + .split_whitespace() + .map(|v| v.parse().unwrap()) + .collect(), + } + } +} + +#[derive(Debug, Clone)] +pub struct Calibrator { + equations: Vec, +} + +impl Calibrator { + pub fn get_valid_sum(&self) -> u64 { + self.equations + .iter() + .filter(|v| v.can_be_valid()) + .map(|v| v.result) + .sum() + } +} + +impl From<&str> for Calibrator { + fn from(value: &str) -> Self { + Self { + equations: value.lines().map(|v| v.into()).collect(), + } + } +} + +type Data = Calibrator; impl DayImpl for Day { fn init_test() -> (Self, Data) { Self::init(include_str!("test_inputs/test07.txt")) } fn expected_results() -> (Answer, Answer) { - (Answer::Number(0), Answer::Number(0)) + (Answer::Number(3749), Answer::Number(0)) } fn init(input: &str) -> (Self, Data) { - ( - Self {}, - input - .lines() - .map(|v| v.parse::().expect("error while parsing input.")) - .collect(), - ) + (Self {}, input.into()) } fn one(&self, data: &mut Data) -> Answer { - Answer::Number(data.len() as u64) + Answer::Number(data.get_valid_sum()) } fn two(&self, data: &mut Data) -> Answer { - Answer::Number(data.len() as u64) + Answer::Number(0) } } diff --git a/src/days/test_inputs/test07.txt b/src/days/test_inputs/test07.txt index e69de29..fc6e099 100644 --- a/src/days/test_inputs/test07.txt +++ b/src/days/test_inputs/test07.txt @@ -0,0 +1,9 @@ +190: 10 19 +3267: 81 40 27 +83: 17 5 +156: 15 6 +7290: 6 8 6 15 +161011: 16 10 13 +192: 17 8 14 +21037: 9 7 18 13 +292: 11 6 16 20