diff --git a/examples/2024/07.txt b/examples/2024/07.txt new file mode 100644 index 0000000..fc6e099 --- /dev/null +++ b/examples/2024/07.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 diff --git a/src/bin/2024/07.rs b/src/bin/2024/07.rs new file mode 100644 index 0000000..eac9623 --- /dev/null +++ b/src/bin/2024/07.rs @@ -0,0 +1,181 @@ +#![cfg_attr(debug_assertions, allow(unused_imports))] +use std::ops::{Add, AddAssign, BitXor, Mul}; + +use advent_of_code::{ + numberlength, + strings::{convert_to_array, parsenumber}, +}; +use advent_of_code_macros::{include_data, include_example}; +use log::*; +use num::{pow::Pow, Integer}; + +include_data!(DATA 2024 07); + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +enum Operation { + Add, + Multiply, + Concat, +} + +impl Operation { + fn op< + T: Integer + + Add + + Mul + + Pow + + std::ops::DivAssign + + AddAssign + + From + + Copy, + >( + self, + a: T, + b: T, + ) -> T { + match self { + Operation::Add => a + b, + Operation::Multiply => a * b, + Operation::Concat => { + let ta = a * T::from(10).pow(numberlength(b)); + ta + b + } + } + } +} + +fn get_data(line: &str) -> (u64, Vec) { + let (result, numbers) = line.split_once(':').unwrap(); + + ( + parsenumber(result.trim()), + Vec::from(convert_to_array::<_, _, ' '>(numbers, parsenumber)), + ) +} + +fn test_equation(result: u64, numbers: Vec, ops: Vec) -> bool { + let mut numberiter = numbers.iter(); + let mut opiter = ops.iter(); + let mut calcresult = numberiter.next().unwrap().clone(); + let mut next_number; + debug_assert!(numbers.len() - 1 == ops.len()); + loop { + next_number = numberiter.next().cloned(); + if next_number.is_none() { + return calcresult == result; + } + calcresult = opiter.next().unwrap().op(calcresult, next_number.unwrap()) + } +} + +fn get_ops(len: usize, conf: usize) -> Vec { + let mut shift = 0; + let mut ops = Vec::with_capacity(len); + loop { + match (conf & (0b1 << shift)) >> shift { + 0 => ops.push(Operation::Add), + 1 => ops.push(Operation::Multiply), + _ => unreachable!(), + }; + shift += 1; + if ops.len() == len { + break; + } + } + ops +} + +fn get_ops_with_concat(len: u32) -> Vec> { + let mut ops = Vec::with_capacity(3u64.saturating_pow(len) as usize); + for i in [Operation::Add, Operation::Concat, Operation::Multiply] { + if len > 1 { + for mut oplist in get_ops_with_concat(len - 1) { + oplist.insert(0, i); + ops.push(oplist); + } + } else { + ops.push(vec![i]); + } + } + ops +} + +#[inline] +fn pow2(i: usize) -> usize { + 2_u64.pow(i as u32) as usize - 1 +} + +fn solution1(data: Vec<(u64, Vec)>) -> u64 { + let mut output = 0; + for line in data { + for i in 0..=pow2(line.1.len()) { + if test_equation(line.0, line.1.clone(), get_ops(line.1.len() - 1, i)) { + output += line.0; + break; + } + } + } + output +} + +fn solution2(data: Vec<(u64, Vec)>) -> u128 { + let mut output = 0; + for line in data { + for ops in get_ops_with_concat((line.1.len() - 1) as u32) { + if test_equation(line.0, line.1.clone(), ops) { + output += line.0 as u128; + break; + } + } + } + output +} + +fn main() { + let data = convert_to_array::<_, _, '\n'>(DATA, get_data); + println!("Found Calibration Total: {}", solution1(data.clone())); + println!("Calibration total with Concat: {}", solution2(data.clone())); +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_test_equation() { + for c in [ + ( + 190, + Vec::from([10, 19]), + Vec::from([Operation::Multiply]), + true, + ), + ( + 3267, + Vec::from([81, 40, 27]), + Vec::from([Operation::Add, Operation::Multiply]), + true, + ), + ( + 3267, + Vec::from([81, 40, 27]), + Vec::from([Operation::Multiply, Operation::Add]), + true, + ), + ( + 292, + Vec::from([11, 6, 16, 20]), + Vec::from([Operation::Add, Operation::Multiply, Operation::Add]), + true, + ), + ( + 292, + Vec::from([11, 6, 16, 20]), + Vec::from([Operation::Add, Operation::Multiply, Operation::Multiply]), + false, + ), + ] { + assert_eq!(test_equation(c.0, c.1.into(), c.2.into()), c.3) + } + } +}