On with Advent of Code puzzle 6 from 2021: solving with hyperoperators.

Today’s puzzle was “easier” from my point of view, in the sense that I had a precise idea of how to address it since the beginning. I will not show the initial solution, though, but a transformed version that gave me an occasion to look at hyperoperators.

sub part-all ($filename where *.IO.e) {
   my (%counts);;
   for $filename.IO.lines {
      my ($p1, $p2) = .comb(/ \-? \d+ /).map: {[$^x, $^y]};
      my $deltas = $p2 «-» $p1;
      $deltas = $deltas «/» $deltas».abs.max;
      my $is-hv = ([*] @$deltas) == 0; # is it horizontal/vertical?
      $p2 «+=» $deltas; # move one step ahead to include it too
      while $p1 !~~ $p2 {
         %counts<over-1>{$p1}++ if $is-hv && %counts<1>{$p1}++;
         %counts<over-2>{$p1}++ if           %counts<2>{$p1}++;
         $p1 «+=» $deltas;
   return %counts<over-1 over-2>».keys».elems;

The idea is to sweep through the inputs and use each line, then toss it away. The four input values are parsed via .comb and arranged into two arrays, which end up in $p1 and $p2 respectively. The .map comes handy here in providing us more than one element when we ask for them (via the circumflexed variables $^x and $^y, which act as indicators that the block of code passed to map takes two input parameters).

From here it’s all operations on points, represented as arrays of two values, thanks to the hyperoperators. It’s a bit weird that, with some [Matlab][] background from a lot of time ago, I didn’t catch with these operators before. Maybe Huffman was right: in [Matlab][] operations are upon vectors by default, and you have to put something additional to trigger a different behaviour; here the normal behaviour is the scalar one, and you have to put something additional to make it different.

Anyway, the $delta array eventually contains how much we should “advance” in either coordinate to go from point $p1 up to point $p2. To make sure we also include the input $p2, it is itself increased once by the $delta, so that we can iterate our while condition upon $p1 being different from $p2.

A segment that is either horizontal or vertical will have one of the to differences/increments set to 0, so we can easily test for non-diagonal stuff by multiplying together the components of $delta. This is how $is-hv is initialized.

The hash %counts is populated in four different slots. The ones with shorter names 1 and 2 count the passage of a segment over the specific point, while the ones with longer names over-1 and over-2 keep track of those which see at least two segments intersect. This is later used to figure out the puzzle’s outputs.

At each loop, $p1 is advanced ahead at the end of the operations. This remembers me so much of C.

Well, I think it’s all for today… stay safe and have fun!