TL;DR

On with Advent of Code puzzle 8 from 2021: the first betrayal of Raku ðŸ™„

On december 8th I woke up early. I mean, itâ€™s a bank holiday in Italy, and I was keen on getting some good result in Advent of Code, so why not?

Countdown tickingâ€¦ 4â€¦ 3â€¦ 2â€¦ 1â€¦ open!

I start reading and I donâ€™t know if itâ€™s the early hours, my aging brain, or simply panic but I barely understand whatâ€™s written.

Well, thereâ€™s surely panic, because I do what most of us do under panic: revert to a safe spot. Which, for me, means coding in Perl. So yes, I confess this: my original solution to get the job done was in Perl.

In my defense, I was probably drawn on the dark side by The Treachery of Whales.

Jokes apart, Perl is amazing and regularly saves my day.

One thing I learned is to go fast up to the question. This was so true in this case: the first part of the puzzle is actually a very simple exercise of counting simple stuff, and I could have done it in much less than the 10:36 I actually scored. At least TIL ðŸ˜…

The second part was much harder, and honestly I didnâ€™t want my brittle knowledge of Raku to get in the way.

BUT.

This year Iâ€™m also determined into understanding more of Raku, so I eventually translated my solution into it. And, while on it, I tried to use some specific data structure that have to be imagined in Perl.

As an example, think using a hash to implement a set.

So here I come, repentant but not too much ðŸ˜‰:

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

sub MAIN (\$filename = \$?FILE.subst(/\.raku\$/, '.tmp')) {
my \$inputs = get-inputs(\$filename);
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.lines.map({
my @chunks = .comb: / \w+ /;
my @hints = @chunks.splice(0, 10);
[@hints, @chunks];
}).Array;
}

sub solve (\$inputs) {
return (part1(\$inputs), part2(\$inputs));
}

sub part1 (\$inputs) {
state %cfl = 2 => 1, 4 => 4, 3 => 7, 7 => 8;  # unambiguous lengths
return \$inputs
.map({\$_[1].Slip})            # get only outputs, individually
.grep({%cfl{.chars}:exists})  # filter the right lengths only
.elems;                       # count 'em
}

sub part2 (\$inputs) {
state %cfl = 2 => 1, 4 => 4, 3 => 7;  # unambiguous, used lengths
my \$sum = 0;
for @\$inputs -> (\$hints, \$outputs) {
# first, let's collect a few statistics and detect 1, 4, and 7
my %set;
my \$seen = BagHash.new;
for @\$hints -> \$hint {
\$seen.add(\$_) for my @chars = \$hint.comb: / \w /;
%cfl{my \$n = @chars.elems}:exists or next;
%set{%cfl{\$n}} = @chars.Set;
}

# next, build a mapping from "right" segment name to "jumbled"
# mapping for "a" is by difference from "7" and "1"
my %sof = a => (%set<7> (-) %set<1>).keys[0];

# some frequencies are known
state %known = 4 => 'e', 6 => 'b', 9 => 'f';

# iterate over the %seen statistic to determine the mapping
for \$seen.kv -> \$k, \$n {
if (%known{\$n}:exists) { %sof{%known{\$n}} = \$k }
elsif (\$n == 8) { %sof<c> = \$k if \$k ne %sof<a> }
elsif (\$n == 7) {
my \$right = (%set<4> (-) set(\$k)).elems == 3 ?? 'd' !! 'g';
%sof{\$right} = \$k;
}
}

# with the %sof mapping we can assign a value to each sequence
#my %nfor = (0 .. 9).map: { assemble(%sof, \$_) => \$_ };
my %nfor = assemble(%sof);

# we can determine the output digits at last
\$sum += \$outputs.map(
{
my \$key = .comb(/\w/).sort({\$^a cmp \$^b}).join('');
%nfor{\$key};
}
).join('');
}
return \$sum;
}

sub assemble (%sof) {
state @segments-for = [
[< a b c   e f g >],
[<     c     f   >],
[< a   c d e   g >],
[< a   c d   f g >],
[<   b c d   f   >],
[< a b   d   f g >],
[< a b   d e f g >],
[< a   c     f   >],
[< a b c d e f g >],
[< a b c d   f g >],
];
return (0 .. 9).map: -> \$n {
%sof{@segments-for[\$n].Slip}.sort({ \$^a cmp \$^b }).join('') => \$n
};
}

The margins of this blog are too narrow to put a full explanation of whatâ€™s going onâ€¦ I hope the comments are sufficient!

Stay safe everyone!

Comments? Octodon, , GitHub, Reddit, or drop me a line!