#!/usr/local/bin/perl # day 2022-11 use strict; use warnings; use v5.32; use List::Util qw( product ); use Log::Log4perl (); use Log::Log4perl::Level (); Log::Log4perl->easy_init( Log::Log4perl::Level::to_priority( 'OFF' ) ); # set to 'OFF', 'INFO', 'DEBUG' or 'TRACE' for successively more information my $logger = Log::Log4perl->get_logger(); @ARGV = "input" unless @ARGV; $/ = ''; # set to paragraph mode. Each monkey is treated as one record my @input = <>; my $ITEMS = "items"; my $OPERATION = "Operation"; my $TEST = "Test"; my $TRUE = "true"; my $FALSE = "false"; my $ROUNDS = 20; sub init_monkeys { my @input = @_; my @monkeys; foreach my $monkey ( @input ) { my %monkey; foreach my $attribute ( split /\n/, $monkey ) { next if ( $attribute =~ m/Monkey/ ); my ( $key, $value ) = split /:/ => $attribute; if ( $key =~ m/$ITEMS/ ) { $value =~ s/\s//g; $monkey{ $ITEMS } = [ split /,/ => $value ]; } elsif ( $key =~ m/$OPERATION/ ) { my %operation; my ( $operation, $operand ) = $value =~ m/(\+|\*) (.+)/; $monkey{ $OPERATION } = { "operation" => $operation, "operand" => $operand, }; } elsif ( $key =~ m/$TEST/ ) { ( $monkey{ $TEST } ) = $value =~ m/(\d+)/; } elsif ( $key =~ m/$TRUE/ ) { ( $monkey{ $TRUE } ) = $value =~ m/(\d+)/; } elsif ( $key =~ m/$FALSE/ ) { ( $monkey{ $FALSE } ) = $value =~ m/(\d+)/; } else { die "Could not parse attribute $attribute"; } } push @monkeys => \%monkey; } return @monkeys; } my @monkeys1 = init_monkeys( @input ); my %monkeys1_count; foreach my $round ( 1 .. $ROUNDS ) { my $num = 0; foreach my $monkey ( @monkeys1 ) { $logger->trace( "Monkey $num:" ); while ( @{ $monkey->{ $ITEMS } } ) { my $item = shift @{ $monkey->{ $ITEMS } }; $logger->trace( " Monkey inspects an item with a worry level of $item." ); $monkeys1_count{ $num }++; my $expression = join " ", $item, $monkey->{ $OPERATION }{ operation }, $monkey->{ $OPERATION }{ operand } eq 'old' ? $item : $monkey->{ $OPERATION }{ operand }; $item = eval $expression; $logger->trace( " Worry level is now $item." ); $item = int( $item / 3 ); $logger->trace(" Monkey gets bored with item. ", "Worry level is divided by 3 to $item."); if ( $item % $monkey->{ $TEST } == 0 ) { # true $logger->trace( " Current worry level is divisible by ", "$monkey->{ $TEST }." ); $logger->trace( " Item with worry level $item is thrown to monkey ", "$monkey->{ $TRUE }." ); push @{ $monkeys1[ $monkey->{ $TRUE } ]->{ $ITEMS } } => $item; } else { # false $logger->trace( " Current worry level is not divisible by ", "$monkey->{ $TEST }." ); $logger->trace( " Item with worry level $item is thrown to monkey ", "$monkey->{ $FALSE }." ); push @{ $monkeys1[ $monkey->{ $FALSE } ]->{ $ITEMS } } => $item; } } $num++; } $logger->debug( "After round $round, the monkeys are holding items with these ", "worry levels:" ); foreach my $i ( 0 .. $#monkeys1 ) { $logger->debug( "Monkey $i: ", ( join ", ", @{ $monkeys1[ $i ]->{ $ITEMS } } ) ); } } foreach my $monkey ( sort keys %monkeys1_count ) { $logger->info( "Monkey $monkey inspected items $monkeys1_count{ $monkey } times." ); } my @inspections = reverse( sort { $a <=> $b } ( values %monkeys1_count ) ); say "part 1: ", product @inspections[ 0 .. 1 ];