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