This commit is contained in:
missing 2022-12-11 12:03:48 -06:00
parent 631d12ac32
commit af2e848a66
2 changed files with 227 additions and 0 deletions

226
src/days/day11.rs Normal file
View file

@ -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<u64>,
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<Self, Self::Err> {
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<Self, Self::Err> {
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<Self, Self::Err> {
match s {
"+" => Ok(Self::Add),
"*" => Ok(Self::Mul),
_ => Err(()),
}
}
}
#[aoc_generator(day11)]
fn generator(input: &str) -> Vec<Monkey> {
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<u64>,
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::<Vec<_>>();
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)
}

View file

@ -12,6 +12,7 @@ mod days {
mod day9;
// curse you, rustfmt
mod day10;
mod day11;
}
aoc_lib! { year = 2022 }