#!/usr/bin/env perl6
use v6.c;
class Bot
{
has Int $.number;
has Pair $.low-dest;
has Pair $.high-dest;
has Int @.values = ();
my Bot @known-bots;
my Int @.output;
method bot(Bot:U: Int $number) returns Bot
{
@known-bots[$number] //= Bot.new(:$number);
return @known-bots[$number];
}
method set-dest(Pair $low-dest, Pair $high-dest)
{
$!low-dest = $low-dest;
$!high-dest = $high-dest;
}
method add-value(Int $value)
{
@!values.push($value);
if (@!values.elems == 2) {
# Part 1 answer
# Not very elegant, oh well...
if min(@!values) == 17 and max(@!values) == 61 {
say "Bot $!number is comparing value-61 microchips with value-17 microchips.";
}
if !$!low-dest || !$!high-dest {
die "Bot $!number has two values but no instructions!";
}
else {
if $!low-dest.key eq 'bot' {
Bot.bot($!low-dest.value).add-value(min(@!values));
}
else {
@.output[$!low-dest.value] += min(@!values);
}
if $!high-dest.key eq 'bot' {
Bot.bot($!high-dest.value).add-value(max(@!values));
}
else {
@.output[$!high-dest.value] += max(@!values);
}
@!values = ();
}
}
}
}
my token num { \d+ }
my token dest { bot || output }
my rule init { ^ value <value=num> goes to bot <bot=num> $ }
my rule instr { ^ bot <bot=num> gives low to <dest-low=dest> <value-low=num>
and high to <dest-high=dest> <value-high=num> $ }
sub MAIN(IO() $inputfile where *.f)
{
# Read the input in two passes, first the instructions, then the initializations.
PASS:
for ^2 -> $pass {
LINE:
for $inputfile.lines -> $line {
if $line ~~ &init {
next LINE if $pass == 0;
Bot.bot(+$<bot>).add-value(+$<value>);
}
elsif $line ~~ &instr {
next LINE if $pass == 1;
Bot.bot(+$<bot>).set-dest(~$<dest-low> => +$<value-low>,
~$<dest-high> => +$<value-high>);
}
else {
die "Invalid input: $line";
}
}
}
# Part 2 answer
my @output = Bot.output;
say "The product of outputs 0, 1 and 2 is @output[^3].join('*') = { [*] @output[^3] }.";
}
Comments