day 11
This commit is contained in:
parent
631d12ac32
commit
af2e848a66
226
src/days/day11.rs
Normal file
226
src/days/day11.rs
Normal 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)
|
||||||
|
}
|
|
@ -12,6 +12,7 @@ mod days {
|
||||||
mod day9;
|
mod day9;
|
||||||
// curse you, rustfmt
|
// curse you, rustfmt
|
||||||
mod day10;
|
mod day10;
|
||||||
|
mod day11;
|
||||||
}
|
}
|
||||||
|
|
||||||
aoc_lib! { year = 2022 }
|
aoc_lib! { year = 2022 }
|
||||||
|
|
Loading…
Reference in a new issue