AoC 2023 D6P1, P2: Quadratic Formula or Count

Day 6 problem 1 asks us to consider a series of toy boat races. The longer you have the boat on the charger, the faster it’ll travel during the remaining units of time. With how many different integer charge times can you beat the record distance in that race?

The distance traveled is (ignoring units) tcharge ( ttotal – tcharge); so the answer to the problem can be found directly by using your favorite quadratic solver on tcharge2 – ttotal tcharge + drecord = 0, which will have zero, one, or two real solutions. If it has zero solutions, one solution that’s non-integer, or two non-integer solutions between two consecutive integers, then there are zero integer charge times that beat the record. Otherwise count the number of integers from the floor of the lower solution plus one to the ceiling of the upper minus one. (That sounds weird but math it out — it ensures not merely tying the record but beating it.)

Anyone who remembers algebra and has dignity and self-respect would use this trivial approach.

I wrote a program to count winning charge times by iteration.

my $count = grep { $_ * ($t - $_) > $d } (1 .. $t - 1);

All of the Perl syntax in this program, I’ve already used this year, so there’s nothing new to explain. The only thing that seems worth calling out is that finding “qualifying” members of a list, or even of a small range of numbers, is very conveniently done with grep.

Part 2 says that the columns of numbers in the input don’t represent separate races; the spaces between them were unintentional and the digits should be run together into larger numbers. Having already written this in part 1:

@time = /(\d+)/g if /Time/;
@dist = /(\d+)/g if /Dist/;

it was the pinnacle of laziness efficiency to reuse that digit extraction and join the results together:

$t = join("", /(\d+)/g) if /Time/;
$d = join("", /(\d+)/g) if /Dist/;

But one could also use s/[^\d]+//g to delete everything that’s not a digit, if that’s what floats your boat.

Full Part 1 Program

#!/usr/bin/perl

use warnings;
use strict;

my (@time, @dist);

while (<>) {
@time = /(\d+)/g if /Time/;
@dist = /(\d+)/g if /Dist/;
}

my $prod;
while (@time) {
my $t = shift @time; my $d = shift @dist;

my $count = grep { $_ * ($t - $_) > $d } (1 .. $t - 1);

$prod = defined $prod ? $prod * $count : $count;
}

print "product $prod\n";

Full Part 2 Program

#!/usr/bin/perl

use warnings;
use strict;

my ($t, $d);

while (<>) {
$t = join("", /(\d+)/g) if /Time/;
$d = join("", /(\d+)/g) if /Dist/;
}

my $count = grep { $_ * ($t - $_) > $d } (1 .. $t - 1);

print "count $count\n";

Leave a Reply