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;
|
||||
// curse you, rustfmt
|
||||
mod day10;
|
||||
mod day11;
|
||||
}
|
||||
|
||||
aoc_lib! { year = 2022 }
|
||||
|
|
Loading…
Reference in a new issue