AoC 2023 D4P2: Caching Coefficients of Future List Elements

Day 4 part 2 asks us to find the number of winning entries on each line and use that to duplicate the succeeding n lines; and a duplicated line with winning entries multi-duplicates its succeeding lines; all with a promise not to overflow the end of the input list; and then count the total number of instances that occurred.

It would be vaguely entertaining to implement this using a queue of the coefficients of upcoming lines, or using recursion; but I chose simply to build an array of the multipliers that I prepopulate for lines I haven’t seen yet.

my $wins = grep { my $num = $_; grep { $_ == $num } @winning }
split(/\s+/, $mine);

The program begins the same as part 1; but instead of advancing the value of the wins by a particular algorithm, simply capture the count of winning numbers.

# Add the physical instance of this card to however many we've earned.
my $instances = ++ $cards[$. - 1];
$total += $instances;

However many duplicates of this row/card have been earned by previous results, increment it by one for this actual row; set that as the number of instances of this row; and add that to the total instances for the puzzle answer.

# If this was a winner, clone future cards.
if ($wins) {
$cards[$_] += $instances foreach ($. .. $. + $wins - 1);
}

If we had any winners, then add the number of instances of the current card to the instance count of the appropriate next few cards.

( num .. num ) is a Perl range operator that generates a list of values counting from the lower to the upper. (Use with caution on potentially-large lists, though this may have been optimized.) $. is the current line number of the input but it’s 1-based and Perl’s array is 0-based. So the current line of input $. is in array element $. - 1; therefore array element $. holds the number of (extra) instances of the next line of input and element $. + $wins - 1 holds the number of (extra) instances of $wins rows after the current.

Full Program

#!/usr/bin/perl

use warnings;
use strict;

my ($total, @cards);

my $numlistre = qr/(?:\d+\s+)*\d+/;

while (<>) {
my ($winning, $mine) = /($numlistre)\s+\|\s+($numlistre)/
or die "didn't parse line $.:\n$_";
my (@winning) = split(/\s+/, $winning);

my $wins = grep { my $num = $_; grep { $_ == $num } @winning }
split(/\s+/, $mine);

# Add the physical instance of this card to however many we've earned.
my $instances = ++ $cards[$. - 1];
$total += $instances;

# If this was a winner, clone future cards.
if ($wins) {
$cards[$_] += $instances foreach ($. .. $. + $wins - 1);
}
}

print "total: $total\n";

Leave a Reply