day(11): add initial solution
Signed-off-by: Matej Focko <mfocko@redhat.com>
This commit is contained in:
parent
9ff562eef9
commit
585e27eed9
2 changed files with 259 additions and 0 deletions
27
samples/day11.txt
Normal file
27
samples/day11.txt
Normal 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
232
src/bin/day11.rs
Normal 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);
|
Loading…
Reference in a new issue