1
0
Fork 0

day(11): add initial solution

Signed-off-by: Matej Focko <mfocko@redhat.com>
This commit is contained in:
Matej Focko 2022-12-11 13:43:05 +01:00
parent 9ff562eef9
commit 585e27eed9
Signed by: mfocko
GPG key ID: 7C47D46246790496
2 changed files with 259 additions and 0 deletions

27
samples/day11.txt Normal file
View file

@ -0,0 +1,27 @@
Monkey 0:
Starting items: 79, 98
Operation: new = old * 19
Test: divisible by 23
If true: throw to monkey 2
If false: throw to monkey 3
Monkey 1:
Starting items: 54, 65, 75, 74
Operation: new = old + 6
Test: divisible by 19
If true: throw to monkey 2
If false: throw to monkey 0
Monkey 2:
Starting items: 79, 60, 97
Operation: new = old * old
Test: divisible by 13
If true: throw to monkey 1
If false: throw to monkey 3
Monkey 3:
Starting items: 74
Operation: new = old + 3
Test: divisible by 17
If true: throw to monkey 0
If false: throw to monkey 1

232
src/bin/day11.rs Normal file
View file

@ -0,0 +1,232 @@
use std::{cmp::Reverse, collections::VecDeque, mem, str::FromStr};
use aoc_2022::*;
use color_eyre::{eyre::eyre, Report};
use itertools::Itertools;
use tracing::debug;
type Input = Vec<Monkey>;
type Output = usize;
#[derive(Clone)]
enum Operation {
Add(usize),
AddSelf,
Mul(usize),
MulSelf,
}
impl Operation {
fn apply(&self, x: usize) -> usize {
match self {
Self::Add(y) => x + y,
Self::AddSelf => x + x,
Self::Mul(y) => x * y,
Self::MulSelf => x * x,
}
}
}
impl FromStr for Operation {
type Err = Report;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let (_, rhs) = s
.split(" = ")
.collect_tuple()
.ok_or(eyre!("couldn't split operation"))?;
let (l, op, r) = rhs
.split_ascii_whitespace()
.collect_tuple()
.ok_or(eyre!("couldn't split the expression"))?;
if l == r {
match op {
"+" => Ok(Self::AddSelf),
"*" => Ok(Self::MulSelf),
_ => Err(eyre!("invalid operator for old")),
}
} else {
match op {
"+" => Ok(Self::Add(r.parse()?)),
"*" => Ok(Self::Mul(r.parse()?)),
_ => Err(eyre!("invalid operator for old")),
}
}
}
}
#[derive(Clone)]
struct Test(usize, usize, usize);
impl Test {
fn get(&self, worry: usize) -> usize {
let &Test(div, t, f) = self;
if worry % div == 0 {
t
} else {
f
}
}
}
impl FromStr for Test {
type Err = Report;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let (divisor, t_branch, f_branch) = s
.split('\n')
.map(|l| l.split_ascii_whitespace().last().unwrap())
.map(|n| n.parse().unwrap())
.collect_tuple()
.ok_or(eyre!("couldn't parse the test"))?;
Ok(Test(divisor, t_branch, f_branch))
}
}
#[derive(Clone)]
struct Monkey {
items: Vec<usize>,
operation: Operation,
test: Test,
inspections: usize,
}
impl FromStr for Monkey {
type Err = Report;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let (_, items_s, op_s, test_s, t_s, f_s) = s
.split('\n')
.collect_tuple()
.ok_or(eyre!("Couldn't split string correctly"))?;
let items = items_s
.split(": ")
.nth(1)
.ok_or(eyre!("No items present"))?
.split(", ")
.map(|x| x.parse().unwrap())
.collect_vec();
let operation = op_s.parse()?;
let test = vec![test_s, t_s, f_s].join("\n").parse()?;
Ok(Monkey {
items,
operation,
test,
inspections: 0,
})
}
}
fn round(monkeys: &mut Input, lcm: usize, div: bool) {
let mut q: VecDeque<(usize, usize)> = VecDeque::new();
for i in 0..monkeys.len() {
let m = &mut monkeys[i];
for j in 0..m.items.len() {
let mut worry = m.operation.apply(m.items[j]);
if div {
worry /= 3;
}
worry %= lcm;
q.push_back((m.test.get(worry), worry));
m.inspections += 1;
}
m.items.clear();
while let Some((i, w)) = q.pop_front() {
monkeys[i].items.push(w);
}
}
}
fn euclid(a: usize, b: usize) -> usize {
// variable names based off euclidean division equation: a = b · q + r
let (mut a, mut b) = if a > b { (a, b) } else { (b, a) };
while b != 0 {
mem::swap(&mut a, &mut b);
b %= a;
}
a
}
struct Day11;
impl Solution<Input, Output> for Day11 {
fn parse_input<P: AsRef<Path>>(pathname: P) -> Input {
file_to_string(pathname)
.split("\n\n")
.map(|m| m.parse().unwrap())
.collect_vec()
}
fn part_1(input: &Input) -> Output {
let mut monkeys = input.clone();
let lcm = monkeys
.iter()
.map(|m| m.test.0)
.fold(1, |x, y| x * y / euclid(x, y));
for _ in 0..20 {
round(&mut monkeys, lcm, true);
}
monkeys
.iter()
.map(|m| m.inspections)
.sorted_by_key(|&i| Reverse(i))
.take(2)
.product()
}
fn part_2(input: &Input) -> Output {
let mut monkeys = input.clone();
let lcm = monkeys
.iter()
.map(|m| m.test.0)
.fold(1, |x, y| (x * y) / euclid(x, y));
let inspect = vec![
1, 20, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 1000,
];
for r in 0..10000 {
round(&mut monkeys, lcm, false);
if inspect.contains(&(r + 1)) {
debug!(
"Monkeys: {:?}",
monkeys.iter().map(|m| m.inspections).collect_vec()
);
}
}
monkeys
.iter()
.map(|m| m.inspections)
// .inspect(|x| debug!("inspections of monkey: {x}"))
.sorted_by_key(|&i| Reverse(i))
.take(2)
.product()
}
}
fn main() -> Result<()> {
// Day11::run("sample")
Day11::main()
}
test_sample!(day_11, Day11, 10605, 2713310158);