TL;DR

So! Itâ€™s that time of the year again, when Eric Wastl starts unveiling 50 (49?) carefully crafted puzzles attached to a Christmas-related story.

For the story, I think Reddit user aang333 put it in the best way:

Yes, the red thread is so funny!

The first puzzles are usually more on the warm-up side, and this year was no exception. So I decided to try and address them in Raku, at least until Iâ€™ll have to decide between my Perl â€śmuscle memoryâ€ť and the ambition to learn more Raku.

Even day 2 put my patience to some stress test, anyway, because data structures and listy stuff handling is much more precise in Raku and itâ€™s difficult for me to figure out the exact expression to reach the goal I have in mind.

# First puzzle

I was ashamed by my solution after reading stuff from other people. For two reasons.

First, itâ€™s entirely clear that my go-to solution is to implement stuff the Perl way, or so. I mean, thereâ€™s nothing to be ashamed - Perl is amazing and Raku feels so good with some Perl background - but I feel that Iâ€™m somehow missing on a lot of new cool stuff by not exploring metaoperators, rotor and I donâ€™t know what else. Sort of going to a restaurant and always take the few dishes that we know are good, if you know what I mean.

Second, and foremost, the solution to the second part could be much simpler than I coded it. It asks to compare two consecutive values in a sequence of sums calculated on a sliding window of the original data, which I did literally. Except that this was way unnecessary, because comparing two consecutive sums means comparing:

$x_k + \underbrace{x_{k+1} + x_{k+2}} < \underbrace{x_{k+1} + x_{k+2}} + x_{k+3}$

You see? We can get rid of stuff from both sides of the inequality, and compare what remains, i.e.:

$x_k < x_{k+3}$

There you go, no need to sum any window etc, just compare an element with the third successor down the road.

What a shame đź™„

Anyway, for the records, hereâ€™s my code:

#!/usr/bin/env raku
use v6;

sub MAIN ($filename = Nil) { my$inputs = get-inputs($filename //$?FILE.subst(/\.raku$/, '.tmp')); my ($part1, $part2) = solve($inputs);

my $highlight = "\e[1;97;45m"; my$reset     = "\e[0m";
put "part1 $highlight$part1$reset"; put "part2$highlight$part2$reset";
}

sub get-inputs ($filename) {$filename.IO.basename.IO.lines.Array;
} ## end sub get_inputs ($filename = undef) sub solve ($inputs) {
return (part1($inputs), part2($inputs));
}

sub count-increases (@inputs) {
my $count = (1 .. @inputs.end) .map({@inputs[$_] > @inputs[$_ - 1] ?? 1 !! 0 }) .sum; } sub part1 ($inputs) { return count-increases($inputs) } sub part2 ($inputs) {
return count-increases(
(1 ..^ $inputs.end).map({$inputs[($_-1)..($_+1)].sum})
);
}


There are a lot of solutions in the solution megathread; todayâ€™s prize goes to this:

#!/bin/env raku

sub MAIN(Str:D $f where *.IO.e = 'input.txt') { my @n =$f.IO.words;
put 'part 1: ', [+] @n Z< @n[1..*];
put 'part 2: ', [+] @n Z< @n[3..*];
}


It was, by the way, the solution that got me thinking about doing my maths correctly! Apart from the mathematical epiphany, anyway, itâ€™s jam-packed of treasures, just there in plain sight:

• a test for existence of the input filename just there in the signature?!?
• zipping the comparison operator?!?
• summing without .sum?!?

Iâ€™m multiply humbled.

# Second puzzle

The second puzzle is not particularly difficult, and at this time of writing these notes I still have to look at other solutions.

I mean, thereâ€™s a lot to learn from there, but I feel my ego is still recovering from yesterday. Additionallyâ€¦ while coding my solution there was a small voice in the back of my head telling me that surely thereâ€™s some more compact and Raku-ish way to do this!.

Yes, I hear voices in the back of my head.

Only when coding solutions to puzzles anyway.

Whatever.

So hereâ€™s my solution - boring maybe, scarcely idiomatic maybe, but still working Raku code!

#!/usr/bin/env raku
use v6;

sub MAIN ($filename = Nil) { my$inputs = get-inputs($filename //$?FILE.subst(/\.raku$/, '.tmp')); my ($part1, $part2) = solve($inputs);

my $highlight = "\e[1;97;45m"; my$reset     = "\e[0m";
put "part1 $highlight$part1$reset"; put "part2$highlight$part2$reset";
}

sub get-inputs ($filename) {$filename.IO.basename.IO.lines.map: { .split: /\s+/ };
} ## end sub get_inputs ($filename = undef) subset Depth of Int where * >= 0; sub solve ($inputs) {
return (part1($inputs), part2($inputs));
}

sub part1 ($inputs) { my (Depth$depth, $hp) = 0, 0; for @$inputs -> $command { my ($direction, $amount) = @$command;
given $direction { when 'forward' {$hp += $amount } when 'up' {$depth -= $amount } when 'down' {$depth += $amount } default { die 'WTF?!?' } } } return$hp * $depth; } sub part2 ($inputs) {
my (Depth $depth,$hp, $aim) = 0, 0, 0; for @$inputs -> $command { my ($direction, $amount) = @$command;
given $direction { when 'forward' {$hp += $amount;$depth += $aim *$amount }
when 'up'      { $aim -=$amount }
when 'down'    { $aim +=$amount }
default        { die 'WTF?!?'    }
}
}
return $hp *$depth;
}


And, of course, I had to go looking in the day 2 solutions megathread! I know there are a few Raku solutions, but I was fascinated by this (crafted by user Orac1e):

my @dirs = 'input'.IO.words;

put [Ă—] [Z+] @dirs.map: -> $_,$x {
when 'up'      { (0,-$x) } when 'down' { (0,$x) }
when 'forward' { ($x, 0) } } put [Ă—] [Z+] @dirs.map: ->$_, $x { state$a = 0;
when 'up'      { $a -=$x; next }
when 'down'    { $a +=$x; next }
when 'forward' { ($x,$a Ă— $x) } }  I know one day Iâ€™ll write stuff like this and think to that time when I wasnâ€™t able to do itâ€¦ Or, much more probably, this will never happen but still Iâ€™m able to have an intuition about whatâ€™s going on, which is perfectly fine at this stage. So why splitting into words? Well, map is more general in Raku, so you can get multiple elements at a time and this is exactly whatâ€™s going on here. Using the topic as the first argument variable of the code block is the evil genius touch here. It allows sparing a given and go straight to use when checks. After resolving what comes after @dirs, the metaoperators kick in from right to left. So Orac1e first processes all pairs to sum them dimension-wise, then does the final multiplication. Wow. And now, one last candy from seaker, here: my ($x, $aim,$y) X= 0;


This!

Well, enough for today. Give Advent of Code a try, but donâ€™t forget to stay safe!