ETOOBUSY ๐ minimal blogging for the impatient
AoC 2022/11 - Monkey business
TL;DR
On with Advent of Code puzzle 11 from 2022: cheating is bad. BUT cheating gets the job done!
So I confess, this is where I cheated. Only a bit, and to be honest itโs not cheating by the challenge standards. I mean, I came to the solution all by myself, without looking at othersโ solutions before I completed the puzzles myself.
So whatโs the cheating Iโm talking about?
Well, itโs in how I read the inputs:
sub get-inputs ($with-full) {
return [
monkey([79, 98], sub { $^old * 19 }, 23, 2, 3),
monkey([54, 65, 75, 74], sub { $^old + 6 }, 19, 2, 0),
monkey([79, 60, 97], sub { $^old * $^old }, 13, 1, 3),
monkey([74], sub { $^old + 3 }, 17, 0, 1),
] unless $with-full;
return [
monkey([64], sub { $^old * 7 } , 13, 1, 3),
monkey([60, 84, 84, 65], sub { $^old + 7 } , 19, 2, 7),
monkey([52, 67, 74, 88, 51, 61], sub { $^old * 3 } , 5, 5, 7),
monkey([67, 72], sub { $^old + 3 } , 2, 1, 2),
monkey([80, 79, 58, 77, 68, 74, 98, 64], sub { $^old * $^old }, 17, 6, 0),
monkey([62, 53, 61, 89, 86], sub { $^old + 8 } , 11, 4, 6),
monkey([86, 89, 82], sub { $^old + 2 } , 7, 3, 0),
monkey([92, 81, 70, 96, 69, 84, 83], sub { $^old + 4 } , 3, 4, 5),
];
}
sub monkey ($items, &op, $divisor, $next-true, $next-false) {
my %retval =
items => $items,
op => &op,
divisor => $divisor,
true => $next-true,
false => $next-false;
return %retval;
}
Yup, right - they are hardcoded. This works for my puzzle inputs only. Considering that I might even use pencil and paper, massaging the inputs a bit is not a big deal.
Anyway.
The fun part this day was in part 2, where we are requested to potentially deal with humoungous stress levels. I mean, almost literally.
Lucky me that I attended many Algebra courses and remembered one thing or two. Like the fact that these modulo operations would help a lot keeping the stress levels low. It sufficies to do all operations modulo a sufficiently large number, that can cope with all the cases.
Which means: do operations modulo the product of all the different divisibility test denominators.
So, hereโs how a single round goes for me in Raku:
sub round (@monkeys, @stats, $divisor = 1) {
state $period = [*] (2, 3, 5, 7, 11, 13, 17, 19, 23);
for @monkeys.kv -> $i, $monkey {
while $monkey<items>.elems {
my $item = $monkey<items>.shift;
@stats[$i]++;
my $new = ($monkey<op>($item) / $divisor).Int % $period;
if $new %% $monkey<divisor> {
@monkeys[$monkey<true> ]<items>.push: $new
}
else {
@monkeys[$monkey<false>]<items>.push: $new
}
}
}
}
The calculated $period
is good for both the example data and my
specific puzzle input, YMMV.
At this point, the two parts are solved in the same way, just with different numbers:
sub part1 (@monkeys) {
my @stats;
round(@monkeys, @stats, 3) for ^20;
return [*] @stats.sort.tail(2);
}
sub part2 (@monkeys) {
my @stats;
round(@monkeys, @stats, 1) for ^10000;
return [*] @stats.sort.tail(2);
}
This was also a good occasion to remember about .tail($n)
.
Stay safe folks!