diff --git a/src/solutions/day_07.rs b/src/solutions/day_07.rs new file mode 100644 index 0000000..b0da0fc --- /dev/null +++ b/src/solutions/day_07.rs @@ -0,0 +1,159 @@ +use crate::common::{Answer, Solution}; + +pub struct Day07; + +impl Solution for Day07 { + fn name(&self) -> &'static str { + "Bridge Repair" + } + + fn part_a(&self, input: &str) -> Answer { + let sum = input + .lines() + .map(|l| l.split_once(": ").unwrap()) + .map(|(a, b)| { + let nums = b + .split_whitespace() + .map(|n| n.parse::().unwrap()) + .collect::>(); + + (a.parse::().unwrap(), nums) + }) + .filter_map(|(total, nums)| { + let max = 2u32.pow(nums.len() as u32); + + for i in 0..max { + let bits = Operation::from_binary(i, nums.len() - 1); + let mut nums = nums.iter(); + let mut computed = *nums.next().unwrap(); + + for (&num, op) in nums.zip(bits) { + computed = op.apply(computed, num); + } + + if computed == total { + return Some(total); + } + } + + None + }) + .sum::(); + + Answer::Number(sum) + } + + fn part_b(&self, input: &str) -> Answer { + let sum = input + .lines() + .map(|l| l.split_once(": ").unwrap()) + .map(|(a, b)| { + let nums = b + .split_whitespace() + .map(|n| n.parse::().unwrap()) + .collect::>(); + + (a.parse::().unwrap(), nums) + }) + .filter_map(|(total, nums)| { + let max = 3u32.pow(nums.len() as u32); + + for i in 0..max { + let bits = Operation::from_ternary(i, nums.len() - 1); + let mut nums = nums.iter(); + let mut computed = *nums.next().unwrap(); + + for (&num, op) in nums.zip(bits) { + computed = op.apply(computed, num); + } + + if computed == total { + return Some(total); + } + } + + None + }) + .sum::(); + + Answer::Number(sum) + } +} + +#[derive(Debug)] +enum Operation { + Addition, + Multiplication, + Concatenation, +} + +impl Operation { + fn from_binary(mut number: u32, length: usize) -> Vec { + let mut vec = Vec::with_capacity(length); + + while number != 0 || vec.len() < length { + vec.push(Self::parse_mod(number % 2)); + number >>= 1; + } + + vec + } + + fn from_ternary(mut number: u32, length: usize) -> Vec { + let mut vec = Vec::with_capacity(length); + + for _ in 0..length { + vec.push(Self::parse_mod(number)); + number /= 3; + } + + vec + } + + fn parse_mod(num: u32) -> Self { + match num % 3 { + 0 => Self::Addition, + 1 => Self::Multiplication, + 2 => Self::Concatenation, + _ => unreachable!(), + } + } + + fn apply(&self, a: u64, b: u64) -> u64 { + match self { + Operation::Addition => a + b, + Operation::Multiplication => a * b, + Operation::Concatenation => format!("{a}{b}").parse::().unwrap(), + } + } +} + +#[cfg(test)] +mod test { + use super::Day07; + use crate::common::Solution; + + use indoc::indoc; + + const INPUT: &str = indoc! {" + 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 + "}; + + #[test] + fn part_a() { + assert_eq!(Day07.part_a(INPUT), 3749.into()); + } + + #[test] + fn part_b() { + assert_eq!(Day07.part_b(INPUT), 11387.into()); + } +} diff --git a/src/solutions/mod.rs b/src/solutions/mod.rs index 35baf53..43cb192 100644 --- a/src/solutions/mod.rs +++ b/src/solutions/mod.rs @@ -6,6 +6,7 @@ mod day_03; mod day_04; mod day_05; mod day_06; +mod day_07; pub const SOLUTIONS: &[&dyn Solution] = &[ &day_01::Day01, @@ -14,4 +15,5 @@ pub const SOLUTIONS: &[&dyn Solution] = &[ &day_04::Day04, &day_05::Day05, &day_06::Day06, + &day_07::Day07, ];