From af2e848a663e68de340d0b9da5a3bee26b2f0a6d Mon Sep 17 00:00:00 2001 From: missing Date: Sun, 11 Dec 2022 12:03:48 -0600 Subject: [PATCH] day 11 --- src/days/day11.rs | 226 ++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + 2 files changed, 227 insertions(+) create mode 100644 src/days/day11.rs diff --git a/src/days/day11.rs b/src/days/day11.rs new file mode 100644 index 0000000..b78e1e7 --- /dev/null +++ b/src/days/day11.rs @@ -0,0 +1,226 @@ +use std::{collections::VecDeque, str::FromStr}; + +use aoc_runner_derive::{aoc, aoc_generator}; +use itertools::Itertools; + +struct Monkey { + num: u32, + starting_items: Vec, + operation: Operation, + test: u64, + if_true: u32, + if_false: u32, +} + +#[derive(Clone, Copy)] +struct Operation { + lhs: Val, + op: Operator, + rhs: Val, +} + +impl Operation { + fn eval(self, old: u64) -> u64 { + match self.op { + Operator::Add => self.lhs.eval(old).checked_add(self.rhs.eval(old)).unwrap(), + Operator::Mul => self.lhs.eval(old).checked_mul(self.rhs.eval(old)).unwrap(), + } + } +} + +impl FromStr for Operation { + type Err = (); + + fn from_str(s: &str) -> Result { + let (lhs, op, rhs) = s.split(' ').collect_tuple().unwrap(); + + Ok(Self { + lhs: lhs.parse()?, + op: op.parse()?, + rhs: rhs.parse()?, + }) + } +} + +#[derive(Clone, Copy)] +enum Val { + Old, + Num(u64), +} + +impl Val { + fn eval(self, old: u64) -> u64 { + match self { + Val::Old => old, + Val::Num(num) => num, + } + } +} + +impl FromStr for Val { + type Err = (); + + fn from_str(s: &str) -> Result { + if s == "old" { + Ok(Self::Old) + } else if let Ok(num) = s.parse() { + Ok(Self::Num(num)) + } else { + Err(()) + } + } +} + +#[derive(Clone, Copy)] +enum Operator { + Add, + Mul, +} + +impl FromStr for Operator { + type Err = (); + + fn from_str(s: &str) -> Result { + match s { + "+" => Ok(Self::Add), + "*" => Ok(Self::Mul), + _ => Err(()), + } + } +} + +#[aoc_generator(day11)] +fn generator(input: &str) -> Vec { + input + .split("\n\n") + .enumerate() + .map(|(i, s)| { + let lines: (_, _, _, _, _, _) = s.lines().collect_tuple().unwrap(); + + let num = lines + .0 + .strip_prefix("Monkey ") + .unwrap() + .strip_suffix(':') + .unwrap() + .parse() + .unwrap(); + + assert_eq!(num, i as u32); + + let starting_items = lines + .1 + .strip_prefix(" Starting items: ") + .unwrap() + .split(',') + .map(|v| v.trim().parse().unwrap()) + .collect(); + + let operation = lines + .2 + .strip_prefix(" Operation: new = ") + .unwrap() + .parse() + .unwrap(); + + let test = lines + .3 + .strip_prefix(" Test: divisible by ") + .unwrap() + .parse() + .unwrap(); + + let if_true = lines + .4 + .strip_prefix(" If true: throw to monkey ") + .unwrap() + .parse() + .unwrap(); + + let if_false = lines + .5 + .strip_prefix(" If false: throw to monkey ") + .unwrap() + .parse() + .unwrap(); + + Monkey { + num, + starting_items, + operation, + test, + if_true, + if_false, + } + }) + .collect() +} + +struct MonkeyState { + items: VecDeque, + inspection_count: u64, +} + +fn stuff_slinging_simian_shenanigans( + input: &[Monkey], + rounds: u32, + mut post_inspection_cb: impl FnMut(&mut u64), +) -> u64 { + let mut states = input + .iter() + .map(|v| MonkeyState { + items: v.starting_items.iter().copied().collect(), + inspection_count: 0, + }) + .collect::>(); + + for _ in 0..rounds { + for monkey in input { + loop { + let state = &mut states[monkey.num as usize]; + + if let Some(mut item) = state.items.pop_front() { + item = monkey.operation.eval(item); + state.inspection_count += 1; + post_inspection_cb(&mut item); + + if item % monkey.test == 0 { + states[monkey.if_true as usize].items.push_back(item); + } else { + states[monkey.if_false as usize].items.push_back(item); + } + } else { + break; + } + } + } + } + + let (a, b) = states.iter().fold((0, 0), |(mut a, mut b), state| { + let mut inspection_count = state.inspection_count; + + if inspection_count > a { + std::mem::swap(&mut a, &mut inspection_count); + } + + if inspection_count > b { + std::mem::swap(&mut b, &mut inspection_count); + } + + (a, b) + }); + + a * b +} + +#[aoc(day11, part1)] +fn part1(input: &[Monkey]) -> u64 { + stuff_slinging_simian_shenanigans(input, 20, |item| *item /= 3) +} + +#[aoc(day11, part2)] +fn part2(input: &[Monkey]) -> u64 { + let max_modulo: u64 = input.iter().map(|v| v.test).product(); + + stuff_slinging_simian_shenanigans(input, 10000, |item| *item %= max_modulo) +} diff --git a/src/lib.rs b/src/lib.rs index 68fc459..59c9d65 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,6 +12,7 @@ mod days { mod day9; // curse you, rustfmt mod day10; + mod day11; } aoc_lib! { year = 2022 }