ETOOBUSY 🚀 minimal blogging for the impatient
Advent of Code 2018/04 made me feel old
TL;DR
Advent of Code 2018 puzzle 4 made me feel old.
As I see it, I started toying with Advent of Code 2018 about in mid-May this year, and stopped at puzzle 4 at the beginning of June.
It’s not particularly difficult, which is probably… the problem. It gave me the subtle feeling that there had to be a very quick and dirty solution to it, but I didn’t actually know what that looked like.
So I avoided this puzzle for a few months, thinking (hoping?) that an elegant solution would come out. Until a few days ago, when I thought that enough is enough and it was time to do the hard coding job. Which made me feel old.
Then I thought: well, let’s do this in Raku! And I felt old even more, because I coded my solution with a strong Perl accent, and my thoughts constantly went to all people that know how to bend Raku to their will and make wonders with a few lines. Heck, I even struggled with parsing the inputs!
Anyway, here’s my solution:
#!/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) {
my @inputs = $filename.IO.basename.IO.lines.sort({$^a leg $^b})
.map: {
when /\d+ \: (\d+) \] \s+ falls/ { ('sleep', $0) }
when /\d+ \: (\d+) \] \s+ wakes/ { ('wake', $0) }
when /Guard \s+ '#' (\d+) / { ('start', $0) }
default { die $_ }
};
return @inputs;
} ## end sub get_inputs ($filename = undef)
sub solve ($inputs) {
return (part1($inputs), part2($inputs));
}
sub part1 ($inputs) {
my %minutes-for;
my %slots-for;
my ($guard, $start);
my ($max-guard, $max-sleep) = (0, 0);
for @$inputs -> $input {
my ($action, $param) = @$input;
with $action {
when 'sleep' {
$start = $param;
}
when 'wake' {
(%slots-for{$guard} //= []).push($start ..^ $param);
my $mins = %minutes-for{$guard} += $param - $start;
($max-guard, $max-sleep) = ($guard, $mins)
if $mins > $max-sleep;
}
when 'start' {
$guard = $param;
}
default { die $action }
}
}
my %count-for;
my ($max-minute, $max-count) = (0, 0);
for %slots-for{$max-guard}.List -> $slot {
for @$slot -> $minute {
my $count = ++%count-for{$minute};
($max-minute, $max-count) = ($minute, $count)
if $count > $max-count;
}
}
return $max-guard * $max-minute;
}
sub part2 ($inputs) {
my (%count-for);
my ($max-guard, $max-count, $max-minute) = (0, 0, 0);
my ($guard, $start);
for @$inputs -> $input {
my ($action, $param) = @$input;
with $action {
when 'start' { $guard = $param }
when 'sleep' { $start = $param }
when 'wake' {
for $start ..^ $param -> $minute {
my $count = ++%count-for{$guard}{$minute};
($max-guard, $max-count, $max-minute) =
($guard, $count, $minute) if $count > $max-count;
}
}
default { die 'wtf?!?' }
}
}
return $max-guard * $max-minute;
}
Was this a complete failure? Well… NO! A few take-aways:
- even if old, I still can manage these tasks 😎
- I definitely experienced that optimum is the enemy of good - I could have coded this a lot of time ago!
- I used
with/when
for the first time, and it felt natural.
So, all in all, a good experience 😄