Here is my solution of the first part of Day 12 of this year’s Advent of Code. The point in this solution is that I use multi functions a lot. Well, actually, the whole logic of the program is based on the dispatching rules of the variants of a single multi function.
We start with a ship at point (0, 0) on a 2D map and we’ve got a list of instructions such as:
F10 N3 F7 R90 F11
The letters N, S, W, and E mean that you have to move the position the given distance North, South, West, or East. The commands L or R mean that you have to rotate the ship itself anticlockwise or clockwise by 90, 180, or 270 degrees. Initially, the ship looked East.
The task is to tell how far from the beginning your ship finds itself after it followed all the instructions.
Here is my solution.
my ($x, $y) = 0, 0; my @dirs = <E N W S>; my $dir = 0; # E for 'input.txt'.IO.lines -> $line { $line ~~ /(\w) (\d+)/; move($/[0].Str, $/[1].Int); } say $x.abs + $y.abs; multi sub move('L', $deg) { $dir = ($dir + $deg / 90) % 4 } multi sub move('R', $deg) { $dir = ($dir - $deg / 90) % 4 } multi sub move('E', $dist) { $x += $dist } multi sub move('N', $dist) { $y += $dist } multi sub move('W', $dist) { $x -= $dist } multi sub move('S', $dist) { $y -= $dist } multi sub move('F', $dist where $dir == 0) { $x += $dist } multi sub move('F', $dist where $dir == 1) { $y += $dist } multi sub move('F', $dist where $dir == 2) { $x -= $dist } multi sub move('F', $dist where $dir == 3) { $y -= $dist }
The file with instructions is read line by line, and then a call to move()
happens. I have a bunch of such functions for each possible case.
Notice that the variants treat the second argument differently. In the first case, it means degrees, in all other cases, it is distance. But in any case, Raku can distinguish the functions by its first argument.
With F, the things are a bit different. Both the first and the second arguments of the four variants of move('F', $dist)
are the same, but there’s also the where
clause, which—and that’s the point!—uses the current value of a global variable. So, it does not look at the arguments the function receives, but it still dispatches its behaviour based on a variable.
* * *
→ Browse the code on GitHub
→ See all blog posts on Advent of Code 2020
I used an enum trick to get away with only one candidate for move(‘F’, $dist) – see https://github.com/mscha/aoc/blob/master/aoc2020/aoc12
But even without that trick, you could have used:
multi sub move(‘F’, $dist where $dir == 0) { move(@dirs[$dir], $dist) }
Correction:
I used an enum trick to get away with only one candidate for move(‘F’, $dist) – see https://github.com/mscha/aoc/blob/master/aoc2020/aoc12
But even without that trick, you could have used:
multi sub move(‘F’, $dist) { move(@dirs[$dir], $dist) }
That’s good indeed.