Let me start with the basic and the most effective (non necessarily the most efficient) form of computing the factorial of a given integer number:

say [*] 1..10;# 3628800

In the below examples, we mostly will be dealing with the factorial of 10, so remember the result. But to make the programs more versatile, let us read the number from the command line:

unit sub MAIN($n);say [*] 1..$n;

To run the program, pass the number:

$ raku 00-cmd.raku 10 3628800

The program uses the reduction meta-operator `[ ]`

with the main operator `*`

in it.

You can also start with 2 (you can even compute *0!* and *1!* this way).

unit sub MAIN($n); say [*]2..$n;

The second solution is using a postfix `for`

loop to multiply the numbers in the range:

unit sub MAIN($n); my $f = 1;$f *= $_ for 2..$n; say $f;

This solution is not that expressive but still demonstrates quite a clear code.

You can also use `map`

that is applied to a range:

unit sub MAIN($n); my $f = 1;(2..$n).map: $f *= *;say $f;

Refer to my article All the stars of Perl 6, or * ** * to learn more about how to read `*= *`

.

Let’s implement a recursive solution.

unit sub MAIN($n); sub factorial($n) { if $n < 2 {return 1;} else {return $n * factorial($n - 1);} } say factorial(n);

There are two branches, one of which terminates recursion.

The previous program can be rewritten to make a code with less punctuation:

unit sub MAIN($n); sub factorial($n) {return1 if $n < 2;return$n * factorial($n - 1); } say factorial($n);

Here, the first `return`

is managed by a postfix `if`

, and the second `return`

can only be reached if the condition in `if`

is false. So, neither an additional Boolean test nor `else`

is needed.

What if you need to compute a factorial of a relatively big number? No worries, Raku will just do it:

say [*] 1..500;

The speed is more than acceptable for any practical application:

raku 06-long-factorial.raku0.14suser 0.02s system 124% cpu 0.127 total

Let’s try something opposite and compute a factorial, which can fit a native integer:

unit sub MAIN($n); myint$f = 1; $f *= $_ for 2..$n; say $f;

I am using a `for`

loop here, but notice that the type of `$f`

is a native integer (thus, 4 bytes). This program works with the numbers up to 20:

$ raku 07-int-factorial.raku202432902008176640000

The fun fact is that you can add a dot to the first program

unit sub MAIN($n); say [*] 1...$n;

Now, `1 ... $n`

is a sequence. You can start it with `2`

if you are not planning to compute a factorials of 0 and 1.

Unlike the solution with a range, it is possible to swap the ends of the sequence:

unit sub MAIN($n); say [*]$n ...1;

Nothing stops us from defining the elements of the sequence with a code block. The next program shows how you do it:

unit sub MAIN($n); my @f =1, * * ++$ ... *; say @f[$n];

This time, the program generates a sequence of factorials from *1!* to *$n!*, and to print the only one we need, we take the value from the array as `@f[$n]`

. Notice that the sequence itself is lazy and its right end is undefined, so you can’t use `@f[*-1]`

, for example.

The rule here is ** * * ++$** (

`$`

.The idea of the solutions 4 and 5 with two branches can be further transformed to using `multi`

-functions:

unit sub MAIN($n);multisub factorial(1) { 1 }multisub factorial($n) { $n * factorial($n - 1) } say factorial($n);

For the numbers above 1, Raku calls the second variant of the function. When the number comes down to 1, recursion stops, because the first variant is called. Notice how easily you can create a variant of a function that only reacts to the given value.

The previous program loops infinitely if you try to set `$n`

to 0. One of the simplest solution is to add a `where`

clause to catch that case too.

unit sub MAIN($n); multi sub factorial($nwhere$n < 2) { 1 } multi sub factorial($n) { $n * factorial($n - 1) } say factorial($n);

Here’s another classical Raku solution: modifying its grammar to allow mathematical notation `$n!`

.

unit sub MAIN($n);sub postfix:<!>($n){ [*] 1..$n}say$n!;

A rarely seen Raku’s feature called *methodop* (method operator) that allows you to call a function as it if was a method:

unit sub MAIN($n); sub factorial($n) { [*] 1..$n } say $n.&factorial;

Recursive solutions are perfect subjects for result caching. The following program demonstrates this approach.

unit sub MAIN($n); use experimental :cached; sub f($n)is cached{ say "Called f($n)"; return 1 if $n < 2; return $n * f($n - 1); } say f($n div 2); say f(10);

This program first computes a factorial of the half of the input number, and then of the number itself. The program logs all the calls of the function. You can clearly see that, say, the factorial of 10 is using the results that were already computed for the factorial of 5:

$ raku 15-cached-factorial.raku 10 Called f(5) Called f(4) Called f(3) Called f(2) Called f(1) 120 Called f(10) Called f(9) Called f(8) Called f(7) Called f(6) 3628800

Note that the feature is experimental.

The reduction operator that we already used has a special variant `[\ ]`

that allows to keep all the intermediate results. This is somewhat similar to using a sequence in the example 10.

unit sub MAIN($n); my @f =[\*]1..$n; say @f[$n - 1];

Now a few programs that go beyond the factorials themselves. The first program computes the value of the expression `a! / b!`

, where both `a`

and `b`

are integer numbers, and `a`

is not less than `b`

.

The idea is to optimise the solution to skip the overlapping parts of the multiplication sequences. For example, `10! / 5!`

is `6 * 7 * 8 * 9 * 10`

.

To have more fun, let us modify Raku’s grammar so that it really parses the above expression.

unit sub MAIN($a, $b where $a >= $b); class F { has $.n; } subpostfix:<!>(Int $n){ F.new(n => $n) } subinfix:</>(F $a, F $b){ [*] $b.n ^.. $a.n }say $a! / $b!;

We already have seen the `postfix:<!>`

operator. To catch division, another operator is defined, but to prevent catching the division of data of other types, a proxy class `F`

is introduced.

To keep proper processing of expression such as `4 / 5`

, define another `/`

operator that catches things which are not `F`

. Don’t forget to add `multi`

to both options. The `callsame`

built-in routine dispatches control to built-in operator definitions.

. . .multisub infix:</>(F $a, F $b) { [*] $b.n ^.. $a.n }multisub infix:</>($a, $b){callsame} say $a! / $b!;say 4 / 5;

Let’s try to reduce the number of multiplications. Take a factorial of 10:

10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1

Now, take one number from each end, multiply them, and repeat the procedure:

10 * 1 = 10 9 * 2 = 18 8 * 3 = 24 7 * 4 = 28 6 * 5 = 30

You can see that every such result is bigger than the previous one by 8, 6, 4, and 2. In other words, the difference reduces by 2 on each iteration, starting from 10, which is the input number.

The whole program that implements this algorithm is shown below:

unit sub MAIN( $n is copywhere $n %% 2#= Even numbers only ); my $f = $n;my $d = $n - 2; my $m = $n + $d;while $d > 0 {$f *= $m;$d -= 2;$m += $d;} say $f;

It only works for even input numbers, so it contains a restriction reflected in the `where`

clause of the `MAIN`

function. As homework, modify the program to accept odd numbers too.

Before wrapping up, let’s look at a couple of exotic methods, which, however, can be used to compute factorials of non-integer numbers (or, to be stricter, to compute what can be called extended definition of it).

The proper way would be to use the Gamma function, but let me illustrate the method with a simpler formula:

An integral is a sum by definition, so let’s make a straightforward loop:

unit sub MAIN($n); my num $f = 0E0; my num $dx = 1E-6; loop (my $x = $dx; $x <= 1; $x += $dx) { $f += (-log($x)) ** $n; } say $f * $dx;

With the given step of `1E-6`

, the result is not that exact:

$ raku 19-integral-factorial.raku 10 3086830.6595557937

But you can compute a ‘factorial’ of a floating-point number. For example, `5!`

is 120 and `6!`

is 720, but what is `5.5!`

?

$ raku 19-integral-factorial.raku 5.5 285.948286477563

And finally, the Stirling’s formula for the rescue. The bigger the *n*, the more correct is the result.

The implementation can be as simple as this:

unit sub MAIN($n); # τ = 2 * π say (τ * $n).sqrt * ($n / e) ** $n;

But you can make it a bit more outstanding if you have a fixed `$n`

:

say sqrt(τ * 10) * (10 / e)¹⁰;

* * *

And that’s it for now. You can find the source code of all the programs shown here in the GitHub repository github.com/ash/factorial.

]]>The grant was approved a year and a half ago right before the PerlCon conference in Rīga. I was the organiser of the event, so I had to postpone the course due to high load. During the conference, it was proposed to rename Perl 6, which, together with other stuff, made me think if the course is needed.

After months, the name was settled, the distinction between Perl and Raku became clearer, and, more importantly, external resourses and services, e.g., Rosettacode and glot.io started using the new name. So, now I think it is still a good idea to create the course that I dreamed about a couple of years ago. I started the main work in the middle of November 2020, and by the beginning of January 2021, I had the first part ready.

The current plan includes five parts:

- Raku essentials
- Advanced Raku subjects
- Object-oriented programming in Raku
- Regexes and grammars
- Functional, concurrent, and reactive programming

It differs a bit from the original plan published in the grant proposal. While the material stays the same, I decided to split it differently. Initially, I was going to go through all the topics one after another. Now, the first sections reveal the basics of some topics, and we will return to the same topics on the next level in the second part.

For example, in the first part, I only talk about the basic data types: `Int`

, `Rat`

, `Num`

, `Str`

, `Range`

, `Array`

, `List`

, and `Hash`

and basic usage of them. The rest, including other types (e.g., `Date`

or `DateTime`

) and the methods such as `@array.rotate`

or `%hash.kv`

is delayed until the second part.

Contrary, functions were a subject of the second part initially, but they are now discussed in the first part. So, we now have Part 1 “Raku essentials” and Part 2 “Advanced Raku topics”. This shuffling allowed me to create a liner flow in such a way that the reader can start writing real programs already after they finish the first part of the course.

I must say that it is quite a tricky task to organise the material without backward links. In the ideal course, any topic may only be based on the previously explained information. A couple of the most challenging cases were ranges and typed variables. They both causes a few chicken-and-egg loops.

During the work on the first part, I also prepared a ‘framework’ that generates the navigation through the site and helps with quiz automation. It is hosted as GitHub Pages and uses Jekyll and Liquid for generating static pages, and a couple of Raku programs to automate the process of adding new exercises and highlighting code snippets. Syntax highlighting is done with Pygments.

Returning the to course itself, it includes pages of a few different types:

- The theory that covers the current topic
- Interactive quizzes that accomplish the theory of the topic and/or the section
- Exercises for the material of the whole section
- Answers to the exercises

The quizzes were not part of the grant proposal, but I think they help making a better user experience. All the quizzes have answers and comments. All the exercises are solved and published with the comments to explain the solution, or even to highlight some theoretical aspects.

The first part covers 91 topics and includes 73 quizzes and 65 exercises (with 70 solutions :-). There are about 330 pages in total. The sources are kept in a GitHub repository github.com/ash/raku-course, so people can send pull requiest, etc.

At this point, the first part is fully ready. I may slightly update it if the following parts require additional information about the topics covered in Part 1.

*This text is a grant report, and it is also (a bit modified) published at https://news.perlfoundation.org/post/rakucourse1 on 13 January 2021.*

You are given two strings `$A`

and `$B`

. Write a script to check if the given strings are Isomorphic. Print 1 if they are otherwise 0.

OK, so if the two strings are isomorphic, their characters are mapped: for each character from the first string, the character at the same position in the second string is always the same.

In the stings *abc* and *def*, *a* always corresponds to *d*, *b* to *e*, and *c* to *f*. That’s a trivial case. But then for the string *abca*, the corresponding string must be *defd*.

The letters do not need to go sequentially, so the strings *aeiou* and *bcdfg* are isomorphic too, as well as *aeiou* and *gxypq*. But also *aaeeiioouu* and *bbccddffgg*, or the pair *aeaieoiuo* and *gxgyxpyqp*.

The definition also means that the number of different characters is equal in both strings. But it also means that if we make the pairs of corresponding letters, the number of unique pairs is also the same, right? If *a* matches *x*, there cannot be any other pair with the first letter *a*.

Let’s exploit these observation:

sub is-isomorphic($a, $b) { +(([==] ($a, $b)>>.chars) && ([==] ($a.comb, $b.comb, ($a.comb Z~ $b.comb))>>.unique)); }

First of all, the strings must have the same length.

Then, the strings are split into characters, and the number of unique characters should also be equal. But the collection of the unique pairs from the corresponding letters from both strings should also be of the same size.

Test it:

use Test; # . . . is(is-isomorphic('abc', 'def'), 1); is(is-isomorphic('abb', 'xyy'), 1); is(is-isomorphic('sum', 'add'), 0); is(is-isomorphic('ACAB', 'XCXY'), 1); is(is-isomorphic('AAB', 'XYZ'), 0); is(is-isomorphic('AAB', 'XXZ'), 1); is(is-isomorphic('abc', 'abc'), 1); is(is-isomorphic('abc', 'ab'), 0);

* * *

→ GitHub repository

→ Navigation to the *Raku challenges* post series

The task is to print the sum of a list of expressions with `+`

, `*`

, and parentheses, but the precedence of the operations is equal in the first part of the problem, and is opposite to the standard precedence in the second part.

In other words, 3 + 4 * 5 + 6 is (((3 + 4) * 5) + 6) in the first case and (3 + 4) * (5 + 6) in the second.

Here is the solution. I hope you are impressed too.

use MONKEY-SEE-NO-EVAL; subinfix:<m>($a, $b) { $a * $b } say [+] ('input.txt'.IO.lines.race.map: *.trans('*' => 'm')).map: {EVAL($_)}

The lines with the expressions come from the file input.txt. For each line, I am replacing `*`

with `m`

, which I earlier made an infix operator that actually does multiplication.

For the second part, we need our `m`

to have lower precedence than `+`

. There’s nothing simpler:

sub infix:<m>($a, $b)is looser<+>{ $a * $b }

Parsing and evaluation are done using `EVAL`

.

* * *

→ Browse the code on GitHub

→ See all blog posts on Advent of Code 2020

All this time, more data arrived, and I also made it even more by adding a separate statistics for the regions of Russia, with its 85 subdivisions, which brought the total count of countries and regions up to almost 400.

mysql> select count(distinct cc) from totals; +--------------------+ | count(distinct cc) | +--------------------+ | 392 | +--------------------+ 1 row in set (0.00 sec)

Due to frequent updates that changes data *in the past*, it is not that easy to make incremental update of statistics, and again, I did not expect that I’ll run the site for so long.

mysql> select count(distinct date) from daily_totals; +----------------------+ | count(distinct date) | +----------------------+ | 329 | +----------------------+ 1 row in set (0.00 sec)

The bottom line is that daily generation became clumsy and not smooth. Before summer, the whole website could be regenerated in less than 15 minutes, but now it turned to 40-50 minutes. And I tend to do it twice a day, as a fresh portion of today’s Russian data arrives a few hours after we’ve got a daily update by the Johns Hopkins University (for yesterday’s stats).

But the most scary signals began after the program started crashing with quite unpleasant errors.

Latest JHU data on 12/12/20 Latest RU data on 12/13/20 Generating impact timeline... Generating world data...MoarVM panic: Unable to initialize event loop

Failed to open file /Users/ash/Projects/covid.observer/COVID-19/csse_covid_19_data/csse_covid_19_daily_reports_us/12-10-2020.csv:Too many open files

Generating impact timeline... Generating world data...Not enough positional arguments; needed at least 4in sub per-capita-data at /Users/ash/Projects/covid.observer/lib/CovidObserver/Statistics.rakumod (CovidObserver::Statistics) line 1906

The errors were not consistent, and I managed to re-run the program by pieces to get the update. But none of the errors were easily explainable.

`MoarVM panic`

gives no explanation, but it completely disappears if I run the program in two parts:

$ ./covid.raku fetch $ ./covid.raku generate

instead of a combined run that both fetches the data and generates the statistics:

$ ./covid.raku update

The `Too many open files`

is a strange one as while I process the files in loops, I do not intentionally keep them open. But that error seems to be solved by changing system settings:

$ ulimit -n 10000

The final error, `Not enough positional arguments; needed at least 4`

, is the weirdest. Such thing happens when you call a function that expects a different number of arguments. That never occurred for months after all bugs were found and fixed. It can only be explained by the new piece of data. Indeed, it may happen that some data is missing, but I believe I already found all the cases where I need to provide the function calls with default zero values.

Having all that, and the fact that the program run takes dozens of minutes before you can catch an error, it was quite frustrating.

And here comes Liz!

She proposed to look into the things and actually spent the whole day by first installing the code and all its requirements and then by actually doing that job to run, debug, and re-run. By the end of the day she created a pull request, which made the program **twice** as fast!

Let’s look at the changes. There are three of them (but no, they do not directly answer the above-mentioned three error messages).

The first two changes introduce parallel processing of countries (remember, there are about 400 of what is considered a unique `$cc`

in the program).

my %country-stats = get-known-countries<>.race(:1batch,:8degree).map: -> $cc { $cc => generate-country-stats($cc, %CO, :%mortality, :%crude, :$skip-excel) }

Calling `.race`

on the result of `get-known-countries()`

function improves the previously sequential processing of countries. Indeed, their stats are computed independently, so there’s no reason for one country to wait for another. The parameters of `race`

, the batch size and the number of workers, can probably be tuned to fit your hardware.

The second change is similar, but for another part of the code where the continents are processed in a loop:

for %continents.keys.race(:1batch,:8degree)-> $cont { generate-continent-stats($cont, %CO, :$skip-excel); }

Finally, the third change is to make some counters native integers instead of Raku `Int`

s:

myint$c = $confirmed[$index] // 0; myint$f = $failed[$index] // 0; myint$r = $recovered[$index] // 0; myint$a = $active[$index] // 0;

I understand that this reduces both the memory and the processing time of these variables, but for some reason it also eliminated the error in counting function parameters.

And finally, I want to mention the `<>`

thing that you may have noticed in the first code change. This is the so-called decontainerization operator. What it does is illustrated by this example from the documentation:

use JSON::Tiny; my $config = from-json('{ "files": 3, "path": "/home/some-user/raku.pod6" }'); say $config.raku; # OUTPUT: «${:files(3), :path("/home/some-user/raku.pod6")}» my %config-hash = $config<>; say %config-hash.raku; # OUTPUT: «{:files(3), :path("/home/some-user/raku.pod6")}»

The `$config`

variable is a scalar variable that keeps a hash. To work with it as with a hash, the variable is decontainerized as `$config<>`

. This gives us a proper hash `%config-hash`

.

I think that’s it for now. The main advantage of the above changes is that the program now needs less than 25 minutes to re-generate the whole site and it does not fail.

Well, but it became a bit louder too as Rakudo uses more cores

Thanks, Liz!

]]>You are given a positive number `$N`

. Write a script to count the number of digits and display as you read it.

Example:

```
Input: $N = 1122234
Output: 21321314
as we read "two 1 three 2 one 3 one 4"
```

OK, so we actually don’t have to spell the number of repetitions as I originally thought (and solved ) but we just need to print the number as a digit (yes, I think we are OK to not go beyond 9 repetitions of a digit).

And so, here’s the whole program:

unit sub MAIN(Int $n = 1122234); print .Str.chars ~ .[0] for $n ~~ m:g/ (\d) $0* /; say '';

Maybe we even can gain the line by replacing `$n`

with `@*ARGS[0]`

, but you also may think of how to get rid of the last line that makes the output cleaner.

In the regex, I match a single digit `(\d)`

and then try to find more copies of it: `$0*`

. As there’s a `:g`

adverb, the regex will be applied as many times as needed to cover the whole input.

Inside the main loop, there’s an interesting case: we have a Match object as the topic variable, and I am calling `.Str.chars`

and `.[0]`

on it. This is probably the best illustration of when you explicitly call subscripting brackets as a method.

Here is the output for a couple of inputs:

$ raku ch-1.raku 21321314 $ raku ch-1.raku 12333345556 111243143516

After I looked at Stuart Little’s solution, I realised that I forgot about `map`

existence again. So, here’s an updated solution that eliminates the problem with printing the final newline:

unit sub MAIN(Int $n = 1122234); ($n ~~ m:g/ (\d) $0* /).map({.Str.chars ~ .[0]}).join.say;

You are given an array of positive numbers `@N`

, where value at each index determines how far you are allowed to jump further. Write a script to decide if you can jump to the last index. Print 1 if you are able to reach the last index otherwise 0.

Example:

```
Input: @N = (1, 2, 1, 2)
Output: 1
as we jump one place from index 0 and then twoe places from index 1 to reach the last index.
```

Right, so the input array is actually a list of instructions that moves us over the same instruction list :-).

So, here’s my solution:

unit sub MAIN(*@a); my $pos = 0; $pos += @a[$pos] while @a[$pos] && $pos < @a.end; say $pos == @a.end ?? 1 !! 0;

In the loop, I am moving by the given number of steps towards the end of the data. An important thing is that you have to control not only that the position does not go outside of the array, but also that the current value is not zero (otherwise, you enter an infinite loop).

A couple of test runs for your pleasure:

$ raku ch-2.raku 1 2 1 2 1 $ raku ch-2.raku 2 1 1 0 2 0

* * *

→ GitHub repository

→ Navigation to the *Raku challenges* post series

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

my $window = 25; my @data = 'input.txt'.IO.lines.map: *.Int; say @data[($window ..^ @data).first({ @data[$_] != any(@data[$_ - $window ..^ $_].combinations(2).map: *.sum) })];

The numbers are read from a text file with `IO.lines`

, and are also mapped to integers. This mapping is not really necessary, but let us leave it here just for clarity.

Then, a tricky piece of code. Let me show it in a less concise way:

for $window ..^ @data -> $i { if @data[$i] != any(@data[$i - $window ..^ $i].combinations(2).map: *.sum) { say @data[$i]; last; } }

So, I am scanning the input array and test different two-number combination within a range `$i - $window ..^ $I`

, comparing their sums with the number at position `$i`

. The *any-junction* is used in comarison: `@data[$i] != any(...)`

. If there is at least one such combination, then we found the answer.

The second part of the task is to take the number found in the first part, and then find the first sequence of the numbers that, being added up, give that number. The expected result is the sum of the minimum and the maximum number in that sequence.

my $window = 25; my @data = 'input.txt'.IO.lines.map: *.Int; my $i = ($window ..^ @data).first({ @data[$_] != any(@data[$_ - $window ..^ $_].combinations(2).map: *.sum) }); my $n = @data[$i]; for ^$i -> $j { ([\,] @data[$j ..^ $i]).first: *.sum == $n andthen .sort andthen say(.[0] + .[*-1]) }

The first part of this code is similar to the previous solution with the only exception that I want to save both the index and the value itself.

In the second part, a few interesting Raku features are used. I believe, I used `andthen`

for the first time so far. It allows us to avoid temporary variables. If the result is `Nil`

, then we can safely ignore the code after `andthen`

as it will not be executed.

But before `andthen`

, there’s another construction that requires attention: `[\,]`

. This is a triangular metaoperator that creates a sequence of lists for the given range of input numbers: `@data[$j ..^ $i]`

. After we found such sequence that adds up to `$n`

, we sort it, compute the sum of the first and the last values, and we are done.

* * *

→ Browse the code on GitHub

→ See all blog posts on Advent of Code 2020

nop +0 acc +1 jmp +4 acc +3 jmp -3 acc -99 acc +1 jmp -4 acc +6

The `nop`

code is a no-operation (but it still has a parameter, we’ll use it in the second part). The `acc`

code adds the value to the current state of the accumulator register. And `jmp`

moves the instruction pointer to the given amount of positions forward of backwards (each position is a full instruction with the operation code and the argument). `jmp +1`

means to execute the next instruction.

The first part is to detect the loop in execution flow and stop the program at that moment. The value of the accumulator is the result we need.

I would say we’d better use grammars for this kind of task. But I used simpler ad hoc parsing that you can see in the below program.

my @program; for 'input.txt'.IO.lines -> $line { $line ~~ / (\w+) ' ' (\S+) /; @program.push: { operation => $/[0].Str, argument => $/[1].Int, }; } my %pc; my $pc = 0; my $acc = 0; while !(%pc{$pc}:exists) { my $instruction = @program[$pc]; %pc{$pc} = 1; # say "$pc: $instruction<operation> $instruction<argument>"; given $instruction<operation> { when 'nop' { $pc++; } when 'acc' { $acc += $instruction<argument>; $pc++; } when 'jmp' { $pc += $instruction<argument>; } } } say $acc;

Each line of the program is parsed with a regex `/ (\w+) ' ' (\S+) /`

, and the parsed instruction is saved in the `@program`

array. Then we execute the instructions and also keep track of those that were executed. As soon as `%pc{$pc}:exists`

we know we made a loop, so the program can be stopped and the value of `$acc`

printed.

In the second part of the problem, we need to replace one of the `nop`

or one of the `jmp`

opcodes with, respectively, `jmp`

and `nop`

. It is only possible to make only one such change in the whole program, and this change should eliminate the loop. If such a change makes it possible to reach the end of the program, we succeeded. Accumulator’s value is the expected result.

My approach is to embrace the central part of the program with another loop, where I will try different opcode replacements. In the end, the first good replacement allows us to execute the whole program.

my @program; for 'input.txt'.IO.lines -> $line { $line ~~ / (\w+) ' ' (\S+) /; @program.push: { operation => $/[0].Str, argument => $/[1].Int, }; } my $replacement-pos = 0; my $pc = 0; my $acc; until $pc >= @program.end { my %pc; $pc = 0; $acc = 0; my $nop-jmp = 0; while !(%pc{$pc}:exists) && $pc <= @program.end { my $instruction = @program[$pc]; %pc{$pc} = 1; # say "$pc: $instruction<operation> $instruction<argument>"; my $operation = $instruction<operation>; if $operation eq 'nop' | 'jmp' { if $nop-jmp == $replacement-pos { $operation = $operation eq 'nop' ?? 'jmp' !! 'nop'; # say "REPLACED"; } $nop-jmp++; } given $operation { when 'nop' { $pc++; } when 'acc' { $acc += $instruction<argument>; $pc++; } when 'jmp' { $pc += $instruction<argument>; } } } $replacement-pos++; } say $acc;

* * *

→ Browse the code on GitHub

→ See all blog posts on Advent of Code 2020

light red bags contain 1 bright white bag, 2 muted yellow bags.

dark orange bags contain 3 bright white bags, 4 muted yellow bags.

bright white bags contain 1 shiny gold bag.

muted yellow bags contain 2 shiny gold bags, 9 faded blue bags.

shiny gold bags contain 1 dark olive bag, 2 vibrant plum bags.

dark olive bags contain 3 faded blue bags, 4 dotted black bags.

vibrant plum bags contain 5 faded blue bags, 6 dotted black bags.

faded blue bags contain no other bags.

dotted black bags contain no other bags.

As you see, the rules dictate how you can put bags into other bags. The only characteristics of the bag is its colour. For example, if the bag is dark orange, it can only contain up to 3 bright white bags and up to 4 muted yellow bags.

The first part of the problem is to count the colours of those bag that can contain shiny gold bags (at any level of depth).

My Raku solution is shown below:

my @rules = 'input.txt'.IO.lines; my %rules; for @rules -> $rule { $rule ~~ m:g/ \w+ ' ' \w+ <?before ' bag'> /; my @colours = $/.map: *.Str; # say "@colours[0] <- {@colours[1..*].join(', ')}"; for @colours[1..*] -> $inner { next if $inner eq 'no other'; %rules{$inner}{@colours[0]} = 1; } } my %final; unroll('shiny gold'); # say %final.keys.join(','); say %final.keys.elems; sub unroll($current) { my $outer = %rules{$current}; next unless $outer; for $outer.keys -> $container { # say "'$current' can be found in $container"; next if %final{$container}; # say "\tDid not see $container yet"; %final{$container} = 1; unroll($container); } }

In this solution, I first build an inverted index `%rules`

of colour relations, and then recursively call the `unroll`

function to reveal the possible chains of nested bag placement.

The second task is to think of the rules as of must-follow instructions (so, each dark orange bag must contain three bright white bags and four muted yellow bags. You need to determine how many bags you have to put inside a shiny gold bag.

Well, I solved the second part of the problem, but the result was not correct. So, I do not post the solution here Maybe one day I will add it here.

* * *

→ Browse the code on GitHub

→ See all blog posts on Advent of Code 2020

abc a b c ab ac

We have to count how many times each letter enters in each group. Again, the original task is more storyline-type and you’d better read it in original. I will just show the solution:

say [+] 'input.txt'.IO.slurp.split("\n\n").map: *.lines.join.comb.unique.elems;

Yes, that’s a one-line (I split it in the middle just to make sure it does not break in some unpredictable way).

I read the file as a whole by `.slurp`

, then split it into groups as `.split("\n\n")`

. For each group, I join the lines into a single string `*.lines.join`

and then split into characters and remove the duplicates: `.unique`

. The number (`.elems`

) of unique letters is the desired answer for this group. Add them up using a reduction operator `[+]`

and print.

In the second part of the problem, we only need to take into account the letters that appear in each line of the group. In other words, the number of such letters equals to the number of lines in a group. Hence, the solution:

my @groups = 'input.txt'.IO.slurp.split("\n\n").map: *.lines; say [+] gather for @groups -> $group { my $n = $group.elems; take $group.join.comb.Bag.grep(*.value == $n).elems; }

* * *

→ Browse the code on GitHub

→ See all blog posts on Advent of Code 2020

`BFFFBBFRRR`

: row`70`

, column`7`

, seat ID`567`

.`FFFBBBFRRR`

: row`14`

, column`7`

, seat ID`119`

.`BBFFBBFRLL`

: row`102`

, column`4`

, seat ID`820`

.

The seat number is determined by the row and the column by a simple formula `$row * 8 + $col`

. You should read the original description to get the task more clearly.

If the task is clear, here is my solution for the first part. In the first part, you need to tell the maximum seat number.

my @passes = 'input.txt'.IO.lines.map: *.trans( < F B L R > => < 0 1 0 1 > ); my $max = @passes.max; my ($row, $col) = $max.substr(0, 7), $max.substr(7); $row = "0b$row".Int; $col = "0b$col".Int; my $seat = $row * 8 + $col; say $seat;

First of all, I transform the coding to a proper binary form, and then extract the row and column parts of it using a couple of `substr`

s. The clever thing about the solution is that you can sort the values immediately after you convert them to a binary form. Actually, you even don’t have to replace L and R as these letters are already sorted unlike F and B (but you still will need to convert it later when determining `$row`

and `$col`

.

In the second part, you have to find *the only missing* seat. You should also take into account that the seat numbers do not start with 1. But the seat that we are looking for is neither the first nor the last, so it is definitely surrounded by the neighbours.

my @seats = 'input.txt'.IO.lines.map: *.trans( < F B L R > => < 0 1 0 1 > ); @seats.=map({"0b$_".Int}); @seats.=sort; say 1 + @seats[(^@seats.end).first({@seats[$_] + 1 != @seats[$_ + 1]})];

I am using the `first`

method to find the value, for which there is no next adjusting number that is bigger by 1.

* * *

→ Browse the code on GitHub

→ See all blog posts on Advent of Code 2020

`byr`

(Birth Year)`iyr`

(Issue Year)`eyr`

(Expiration Year)`hgt`

(Height)`hcl`

(Hair Color)`ecl`

(Eye Color)`pid`

(Passport ID)`cid`

(Country ID)

The full record for a single passport contains colon-separated pairs key:value:

iyr:2016 hgt:180cm ecl:amb eyr:2028 cid:237 pid:334803890 byr:1953 hcl:#18171d

First, you have to make sure that all the passports contain all required fields. The required fields are the first eight of the shown above. The `cid`

field is optional. If one of the required fields is missing, the passport is considered invalid. You need to count the number of valid passports.

my @passports = 'input.txt'.IO.slurp.split("\n\n"); my $valid = 0; for @passports -> $passport { my $fields = ($passport.words.map: *.split(':').first).sort.join; $valid++ if $fields eq one <byrcidecleyrhclhgtiyrpid byrecleyrhclhgtiyrpid>; } say $valid;

In my solution, I am extracting the field names from the passport data and join them together (sorted). In this case, the field names should give one of the strings `byrcidecleyrhclhgtiyrpid`

or `byrecleyrhclhgtiyrpid`

, which I check with the* one-junction.*

In the second part, the tests are stricter. You not only have to make sure the fields are there, but also to check that the values are correct. Such as years have four digits and fall into some predefined ranges. Let me not paste the whole program here, as it contains a lot of regexes in the checks and is quite wordy in general. You can find my solution on GitHub. Alternatively, try solving this problem with Raku grammars.

* * *

→ Browse the code on GitHub

→ See all blog posts on Advent of Code 2020

`..##.......`

`#...#...#..`

`.#....#..#.`

`..#.#...#.#`

`.#...##..#.`

`..#.##.....`

`.#.#.#....#`

This pattern is repeated horizontally as many times as needed. In a single step, we can make three moves cells and one row down. It is also OK to pass through the trees, but you need to count them. As soon as you reached the bottom end of the forest, tell how many trees you encountered.

my @trees = 'forest.txt'.IO.lines.map: *.comb.Array; my $height = @trees.elems; my $width = @trees[0].elems; my ($x, $y) = 0, 0; my $trees = 0; while $y < $height { $trees++ if @trees[$y][$x % $width] eq '#'; $x += 3; $y++; } say $trees;

In my solution, I am building the `@trees`

directly from the file by splitting the strings into characters: `'forest.txt'.IO.lines.map: *.comb.Array`

.

Then, a trivial loop with a clever piece: instead of copying the map, I am using the modulo operator to loop the second coordinate: `@trees[$y][$x % $width]`

. The rest is obvious: if you see `#`

at this position, increment the counter.

In the second part of the problem, the moves are different. Instead of ‘three to the right, one down’, the rules are different. You need to go through the forest a few times counting the trees on each pass, and then multiply the results. Here are the move rules for each pass:

- Right 1, down 1.
- Right 3, down 1.
- Right 5, down 1.
- Right 7, down 1.
- Right 1, down 2.

Let us update the program a bit to reflect the new instructions. Notice how the `for`

loop sets the array `@step`

as a loop variable.

#!/usr/bin/env raku my @trees = 'forest.txt'.IO.lines.map: *.comb.Array; my $height = @trees.elems; my $width = @trees[0].elems; my $prod = 1; for [[1, 1], [3, 1], [5, 1], [7, 1], [1, 2]] -> @step { my ($x, $y) = 0, 0; my $trees = 0; while $y < $height { $trees++ if @trees[$y][$x % $width] eq '#'; $x += @step[0]; $y += @step[1]; } # say $trees; $prod *= $trees; } say $prod;

* * *

→ Browse the code on GitHub

→ See all blog posts on Advent of Code 2020

The problem is to check if the passwords satisfy the requirement which is mentioned before the password:

```
1-3 a: abcde
1-3 b: cdefg
2-9 c: ccccccccc
```

The phrase `1-3 a`

means that the character `a`

must appear one to three times in the password, not fewer nor more.

What I do is demonstrated in the following program. The text file is read line by line, and for each of them, I extract the parts using a regex.

Then, the password is transformed into a `Bag`

object which automatically counts the characters in the string, so we can ask for the number by reading it from the `%chars`

hash.

my $good = 0; for 'input.txt'.IO.lines() -> $line { $line ~~ / (\d+) '-' (\d+) ' ' (\w) ': ' (\w+) /; my %chars = $/[3].comb.Bag; $good++ if $/[0] <= (%chars{$/[2]} // 0) <= $/[1]; } say $good;

In the second part of the problem, the validity of passwords is defined differently. In the same input file, the numbers in the interval mean the two positions in the password string, only one of which is allowed to contain the given character.

#!/usr/bin/env raku my $good = 0; for 'input.txt'.IO.lines() -> $line { $line ~~ / (\d+) '-' (\d+) ' ' (\w) ': ' (\w+) /; my @chars = $/[3].comb; $good++ ifone(@chars[$/[0] - 1], @chars[$/[1] - 1]) eq $/[2]; } say $good;

The first part of the program is the same as before, but the test now includes a so-called *one-junction*. We demand that only one of the items equals to the character:

one(@chars[$/[0] - 1], @chars[$/[1] - 1]) eq $/[2]

So simple so true.

* * *

→ Browse the code on GitHub

→ See all blog posts on Advent of Code 2020

So, the problem of Day 1 is to take a long list of integers and find such two neighbouring numbers that add to to 2020. The second part of the task is to find three such numbers.

I saved a list of integers in a separate text file (it is also the case for all further tasks), so I use Raku to read the data from it. Then, we can use the `combinations`

method, which is built-in in Raku and is doing exactly what we need for this task: it takes a list and returns all combinations of 2 or 3 elements:

my @data = 'data.txt'.IO.lines; say [*] @data.combinations(2).first(*.sum == 2020); say [*] @data.combinations(3).first(*.sum == 2020);

And that’s it for this day

* * *

→ Browse the code on GitHub

→ See all blog posts on Advent of Code 2020

* * *

Christmas time, and it’s time to talk to each and every one! It’s a great idea to approach people by speaking their languages. In today’s post, let me demonstrate a number of working solutions of the first problem of Week 89 of The Weekly Challenge in 22 different programming languages. It is a kind of continuation of my last year’s Advent series ‘A Language a Day’.

The problem is to add up all the GCDs of the series of unique pairs of numbers between `1`

and `$N`

including `$N`

.

For example, for the input number `100`

, the summation chain is this one:

GCD(1, 2) + GCD(1, 3) + GCD(1, 4) + ... + GCD(1, 99) + GCD(1, 100) + GCD(2, 3) + GCD(2, 4) + GCD(2, 5) + ... + GCD(2, 99) + GCD(2, 100) + ... ... + GCD(98, 100) + GCD(99, 100)

The answer for this case is `13015`

; it will be our password that confirms that the person we speak to understood us clearly even if we spoke a foreign language.

The solutions are grouped into two parts. In the first group, either a built-in or a library function is used to compute the greatest common divisor. In the second group, the algorithm is implemented directly in the program. In each section, the solutions are listed in the order in which I solved them.

All the programs can be run from the command line and accept the value of `$N`

as the first parameter. If the number is missing, the default value `3`

is used. The result of the program is always a single number printed in the console. You can see instructions of how to run the program exactly in the comment at the beginning of each program.

In Raku, we’ve got all the things required for a compact solution. Actually, the most compact among all the solutions below. So, we’ve got the `combinations`

method to convert a range into unique pairs of numbers and the built-in `gcd`

routine. We also have the pleasure to use reduction operators `[ ... ]`

even if they can be easily replaced. For example, the first usage of it `[+]`

can be replaced with the call of `sum`

, and the second `[gcd] $_`

with something like `$_[0] gcd $_[1]`

. By the way, notice that in Raku, `gcd`

is an infix operator, so you use it in the form of `$a gcd $b`

and not as a function .`gcd($a, $b)`

# Test run: # $ raku ch-1.raku 100 # 13015 my $n = @*ARGS[0] // 3; say [+] (1..$n).combinations(2).map: {[gcd] $_};

In Python, there’s no built-in `gcd`

or `combinations`

, but both are available in the standard library. For diversity, I used `math.gcd`

but implemented the combination creation with two nested `for`

loops. The first loop iterates over the whole range between `1`

and `$N`

, while the inner loop starts with the current value of the outer loop.

# Test run: # $ python3 ch-1.py 100 # 13015 import sys, math n = 3 if len(sys.argv) == 1 else int(sys.argv[1]) s = 0 for x in range(1, n + 1): for y in range(x + 1, n + 1): s += math.gcd(x, y) print(s)

Here is a solution in C++. As the author of the language says, ‘C++ feels like a new language’, and even in this simple task, we can use the library function `gcd`

that is available since the standard C++17.

In the rest, the program also includes two nested loops and accumulates the sum for each combination.

// Compile as: // $ g++ -std=c++17 ch-1.cpp // Test run: // $ ./a.out 100 // 13015 #include#include #include using namespace std; int main(int argc, char** argv) { int n = 3; if (argc != 1) { stringstream input(argv[1]); input >> n; } int s = 0; for (int x = 1; x <= n; x++) { for (int y = x + 1; y <= n; y++) { s += gcd(x, y); } } cout << s << endl; }

Good old modern and future Perl is here! As, among the rest, it is famous for CPAN, let us use a module `Math::Utils`

from there. Actually, this is the only solution where I use a module that is not available in the default installation.

# To run, install Math::Utils first: # $ cpanm Math::Utils # $ perl ch-1.pl 100 # 13015 use v5.20; use Math::Utils qw(gcd); my $n = $ARGV[0] // 3; my $s = 0; for my $x (1 .. $n) { for my $y ($x + 1 .. $n) { $s += gcd($x, $y); } } say $s;

The program in Ruby is also quite compact, I would say. Notice how the `gcd`

method is used here: `x.gcd(y)`

. It is indeed is *a method,* and it is called on one of the numbers. We’ll see more examples of such approach later.

# Usage: # $ ruby ch-1.rb 100 # 13015 n = ARGV.length == 1 ? ARGV[0].to_i : 3 s = 0 for x in 1 .. n for y in x + 1 .. n s += x.gcd(y) end end puts s

In Scala, we have to deal with Java’s legacy and create a class to start the day. But nevertheless, the program is not that big. What you may want to enjoy is possibly the syntax of loop headers: `for (x <- 1 to n)`

with the left arrow. Also notice that the `gcd`

routine is again a method, and it’s a method defined for `BigInt`

s: `BigInt(x).gcd(y)`

.

/* To run: $ scala ch-1.scala 100 13015 */ import math.BigInt object Main { def main(args: Array[String]): Unit = { var n: Int = if (args.size == 1) args(0).toInt else 3 var s: BigInt = 0 for (x <- 1 to n) { for (y <- x + 1 to n) { s = s + BigInt(x).gcd(y) } } println(s) } }

Here is the solution in C#. Welcome to the world of .NET, where many things are clearly spelt out: `BigInteger.GreatestCommonDivisor(x, y)`

. In the rest, here we have the same two nested loops that build the pair of combinations.

// Compile and run on a Mac: // $ csc -r:System.Numerics.dll ch-1.cs // $ mono ch-1.exe 100 // 13015 using System; using System.Numerics; class Program { static int Main(string[] args) { int n = 3; if (args.Length == 1) n = int.Parse(args[0]); var s = new BigInteger(0); for (int x = 1; x <= n; x++) { for (int y = x + 1; y <= n; y++) { s += BigInteger.GreatestCommonDivisor(x, y); } } System.Console.WriteLine(s); return 0; } }

To me, languages built on C++ have their specific charm. On one side, it is the same known language, but on the other, it embeds the things that you were missing earlier (see, for example, how easy it is to deal with command-line arguments). The `gcd`

here is again a method called on a number: `x.gcd(y)`

.

// To run: // $ dart ch-1.dart 100 // 13015 void main(Listargs) { var n = 3; if (args.length == 1) n = int.parse(args[0]); var s = 0; for (var x = 1; x <= n; x++) { for (var y = x + 1; y <= n; y++) { s += x.gcd(y); } } print(s); }

Julia is another interesting language that actually has many similarities with Raku. For our today’s need, there’s a built-in `gcd`

function that I am happily using. The only unexpected obstacle is, maybe, the need to explicitly refer to the accumulator `s`

as to a `global`

variable.

# To run: # $ julia ch-1.jl 100 # 13015 n = length(ARGS) == 1 ? parse(Int, ARGS[1]) : 3 s = 0 for x in range(1, stop = n) for y in range(x + 1, stop = n) global s s += gcd(x, y) end end println(s)

Acter C comes D. And here we are. In the program, you can see extensive use of the `auto`

declarator. I believe, the situation here resembles how some elements of Raku entered back in Perl, even if Raku was a continuation of Perl historically. Similarly, `auto`

is now available in C++ too (while you need to practice not to forget to use `auto`

automatically).

// How to run: // $ rdmd ch1.d 100 // 13015 import std.stdio; import std.numeric; import std.conv; void main(string[] args) { auto n = args.length == 2 ? to!int(args[1]) : 3; auto s = 0; for (auto x = 1; x <= n; x++) { for (auto y = x + 1; y <= n; y++) { s += gcd(x, y); } } writeln(s); }

Move on to a different world (for a bit). Here is the solution in a functional programming language. Well, Common Lisp adds some syntax sugar to help us build loops without manually manipulating loop counters and recursive calls. (Not to say about `setq`

that sets the new value of a variable.)

In any case, it also has the built-in `gcd`

function, which, of course, you call as `(gcd x y)`

. The below program works with the SBCL implementation (mostly because of how it reads the command-line arguments).

;;; How to run: ;;; $ sbcl --script ch-1.lisp 100 ;;; ;;; 13015 (defvar n (parse-integer (nth 1 *posix-argv*))) (defvar s 0) (loop for x from 1 to n do ( loop for y from (+ 1 x) to n do (setq s (+ s (gcd x y))) ) ) (print s) (terpri)

OK, and now we start the second part of the solutions list. Now, the GCD algorithm is implemented directly in the program itself. Refer to this implementation in C; this algorithm is used in all other solutions below.

int gcd(int a, int b) { while (b) { int t = b; b = a % b; a = t; } return a; }

It is important to say that due to the loop organisation, we always call this function with such arguments that `b`

is always bigger than `a`

, so you don’t have to care about other cases.

So, here is the complete program in C:

/* Compile: $ gcc ch-1.c Test run: $ ./a.out 100 13015 */ #include#include int gcd(int a, int b) { while (b) { int t = b; b = a % b; a = t; } return a; } int main(int argc, char** argv) { int n = 3; if (argc != 1) { n = atoi(argv[1]); } int s = 0; for (int x = 1; x <= n; x++) { for (int y = x + 1; y <= n; y++) { s += gcd(x, y); } } printf("%i\n", s); }

A Node.js slash JavaScript program is here for your further entertainment. It resembles a lot the previously shown C program. A similar pair of nested loops, and a similar implementation of `gcd`

. Could you imagine 10-15 years ago that you would be able to run a JS program from command line?

// Test run: // $ node ch-1.js 100 // 13015 let n = process.argv.length == 3 ? process.argv[2] : 3; let s = 0; for (let x = 1; x <= n; x++) { for (let y = x + 1; y <= n; y++) { s += gcd(x, y); } } console.log(s); function gcd(a, b) { while (b) { let t = b; b = a % b; a = t; } return a; }

Now, look at the solution in Java. Yes, we have to use classes again, but in the rest, a nice and clean program that doesn’t require many more comments, I think.

// To run: // $ java ch-1.java 100 // 13015 class Main { static int gcd(int a, int b) { while (b != 0) { int t = b; b = a % b; a = t; } return a; } public static void main(String[] args) { int n = args.length == 1 ? Integer.parseInt(args[0]) : 3; int s = 0; for (int x = 1; x <= n; x++) { for (int y = x + 1; y <= n; y++) { s += gcd(x, y); } } System.out.println(s); } }

The program in Rust is an interesting combination of elements that we are familiar with from both C, JavaScript, and even Perl and Raku (for example, ranges `..`

). Also, a nice addition of built-in type system, and maybe an unusual concept of macros — those ‘functions’ with an exclamation mark in their name such as `println!`

.

// To compile and run: // $ rustc ch-1.rs // $ ./ch-1 100 // 13015 use std::env; fn gcd(a: u32, b: u32) -> u32 { let mut x = a; let mut y = b; while y != 0 { let t = y; y = x % y; x = t; } return x; } fn main() { let args: Vec= env::args().collect(); let n; if args.len() == 2 { n = args[1].parse().unwrap(); } else { n = 3; } let mut s = 0; for x in 1 .. (n + 1) { for y in (x + 1) .. (n + 1) { s += gcd(x, y); } } println!("{}", s); }

I have a question for you. When did you program in Pascal last time? My answer is ‘Something like 30 years ago’. But honestly, that nostalgic mood is a great thing for the evenings around Christmas time. And while there’s no `gcd`

built in, you can implement it yourself if you remember to use `<>`

instead of `!=`

and a single `=`

in comparisons: `if paramCount() = 0 then`

. I also struggled a bit with semicolons, for example, no semicolon allowed before `else`

.

(* To compile and run: $ fpc ch-1.pas $ ./ch-1 100 13015 *) program Challenge89Part1(input, output); uses sysutils; var n, x, y, s: integer; function gcd(a, b: integer): integer; var t: integer; begin while b <> 0 do begin t := b; b := a mod b; a := t; end; gcd := a end; begin if paramCount() = 0 then n := 3 else n := StrToInt(paramStr(1)); s := 0; for x := 1 to n do for y := x + 1 to n do s += gcd(x, y); writeln(s); end.

And now fast forward to the present days. Here is Go with its strict requirements not to leave garbage in the code and use all variables and imported modules. Notice that I used multiple assignments and avoided a temporary variable in the implementation of `gcd`

: `b, a = a%b, b`

. Heh, and the Go standard formatter removed my spaces around the `%`

operator.

// To compile and run: // $ go run ch-1.go 100 // 13015 package main import ( "fmt" "os" "strconv" ) func gcd(a, b int) int { for b != 0 { b, a = a%b, b } return a } func main() { n := 3 if len(os.Args) == 2 { n, _ = strconv.Atoi(os.Args[1]) } s := 0 for x := 1; x <= n; x++ { for y := x + 1; y <= n; y++ { s += gcd(x, y) } } fmt.Println(s) }

Lua is the language that is loved by many people, and I believe there are many cases when its design with tables can be beneficial in many applications. For our practice, I used the standard approach: a few loops, and it’s done. I would still point your attention to the following line: `n = arg[1] and arg[1] or 3`

, which is actually a ternary construction to assign the default value if the argument is missing.

-- How to run: -- $ lua ch-1.lua 100 -- 13015 function gcd(a, b) while b > 0 do t = b b = a % b a = t end return a end n = arg[1] and arg[1] or 3 s = 0 for x = 1, n do for y = x + 1, n do s = s + gcd(x, y) end end print(s)

Going further to some science-related language. For a long time, Fortran was the language in which tons of algorithms were encoded for physics and mathematics. I believe it would be very beneficial to use this as the language to teach students (OK, consider that a joke with some elements of truth) What would be really interesting is to browse into some sophisticated algorithms written decades ago — many of them may be unexpectedly efficient.

! To compile and run: ! ! $ gfortran ch-1.f95 ! $ ./a.out 100 ! 13015 function mygcd(a, b) result(x) integer, intent(in) :: a, b integer :: x, y, t x = a y = b do while (y /= 0) t = y y = mod(x, y) x = t end do end function program challenge89part1 integer :: n, x, y, s character(len=20) :: arg character(len=20) :: nstr if (iargc() == 1) then call getarg(1, nstr) read(nstr,*) n else n = 3 end if s = 0 do x = 1, n do y = x + 1, n s = s + mygcd(x, y) end do end do write(*,*) s end program

Let me introduce another solution with sigils, which, as you may see, is not too frequent part among the languages. Perl, Raku, PHP, and Bash in this list do use them though. I believe, if you are familiar with either Perl or Raku, you can understand every bit of this program in PHP (yeah, and no `my`

declarators).

<?php // Run as: // $ php ch-1.php 100 // 13015 function gcd($a, $b) { while ($b) { $t = $b; $b = $a % $b; $a = $t; } return $a; } $n = $argc == 2 ? $argv[1] : 3; $s = 0; for ($x = 1; $x <= $n; $x++) { for ($y = $x + 1; $y <= $n; $y++) { $s += gcd($x, $y); } } echo "$s\n"; ?>

In the program in Kotlin, we see the use of typed variables, C-like functions and...double-dot ranges! What a surprise for the Perl and Raku lovers again.

// How to run: // $ kotlinc ch-1.kt -include-runtime -d ch1.jar // $ java -jar ch1.jar 100 // 13015 fun gcd(a: Int, b: Int): Int { var x = a var y = b while (y != 0) { val t = y y = x % y x = t } return x } fun main(args: Array) { var n: Int if (args.size == 1) n = args[0].toInt() else n = 3 var s = 0 for (x in 1..n) { for (y in x + 1 .. n) { s += gcd(x, y) } } println(s) }

And the last program on this page. At this point, I could add a poll to ask if you consider Bash a programming language or not. Honestly, I did not think it would be possible to solve today’s problem in Bash, but as you see, the result is not that much more complicated than the solutions in other languages. Enjoy it too!

#!/usr/bin/bash # Usage: # $ bash ch-1.bash 100 # 13015 # # N. B. Try with smaller arguments, as the computations # for 100 as the input can take a while (~ a minute). gcd() { a=$1; b=$2; while [ $b -ne 0 ]; do t=$b b=`expr $a % $b` a=$t done gcd=$a } n=${1:-3} # default is 3 s=0 x=1 while [ $x -le $n ]; do next=`expr $x + 1`; y=$next; while [ $y -le $n ]; do y=`expr $y + 1`; gcd $x $y; s=`expr $s + $gcd`; done x=$next; done echo $s

And that’s it for today. Tomorrow, there’s another post in this Advent Calendar, but don’t forget that there are more calendars this year, and there are more Weekly Challenges coming soon!

]]>Welcome to the monthly series `Meet The Champion`

.

Last month we spoke to **Myoungjin Jeon**, the winner of **September 2020**.

Today we are talking to **Andrew Shitov**, the winner of **October 2020** of `The Weekly Challenge`

. I hope you are going to enjoy the interview.

**Mohammad:** Tell us about your technical background?

**Andrew:** Well, being a **PhD** in **Physics** and **Mathematics**, I used **C++** a lot for computing things happening in nuclear collisions, which in the end turned me to work in the world of programming rather than science. Since then, I was mostly working with the main people driving the Internet and Web in Russia. **Perl** was the main tool, but I was always having fun with other languages and platform, including programming for microcontrollers when it was not the mainstream yet.

**Mohammad:** How/When did you start using **Perl**/**Raku**?

**Andrew:** I started using **Perl** somewhen about just before **2000**. A friend of mine said there’s a language where you can write `if`

either before or after the thing. I believe that was the trigger for me.

By the way, the date is surprisingly close to when **Perl 6** was announced, and I followed it since pretty much the beginning. Therefore the frustration mood when it did not go well or when the **Perls** were battling for the version number, or when it was proposed to be renamed, or when it was finally renamed to the same earlier rejected name, etc. I wonder what to expect in the future

**Mohammad:** How did you come to know about `The Weekly Challenge`

?

**Andrew:** It was not a problem to hear about the initiative if you follow the main news sources about **Perl** and (now) **Raku**. But I can’t say I was enthusiastic about the project. Neither I could predict it lasts for such a long time already. I am looking forward to the 100^{th} issue.

**Mohammad:** What do you like the most about `The Weekly Challenge`

?

**Andrew:** There is no doubt that the main achievement is the number of blog posts that the participants wrote alongside their solutions. The historians should do a research on how that helped **Perl** and **Raku**, but it is also obvious that it did not help much to overcome the borders of the echo chamber.

The second thing — rather on a personal development level — I think it really helps people to attend their programming gym regularly and for free. Most of the tasks are compact enough to be solved in a few minutes. While not taking much time, they are helping in refreshing different programming tricks and techniques, which is a huge help for everyone (of all ages).

**Mohammad:** How much time you dedicate every week to `The Weekly Challenge`

?

**Andrew:** I started solving the tasks since around Week 65, and then retrospectively solved many assignments from earlier weeks. My original idea was to spend half an hour per task at maximum including writing a blog post about the solution.

Then I decided to make weekly reviews of the Raku solutions, which broke the initial plan, so it now takes a bit more than half an hour, which makes it more difficult to follow the schedule diligently.

**Mohammad:** Do you checkout others solutions and who is your favourite?

**Andrew:** Well, the answer is obvious if you’ve just read the previous answer. But seriously, I mostly never look at the other solutions before I finish (and commit) mine. In most cases, I am interested in **Raku** solutions only, but I also lurk into Perl solutions occasionally.

Speaking of **Raku** solutions, I honestly enjoy most of them. There are solutions which I find written in a foreign style for me, but on the other hand, they often demonstrate such great pearls of Raku that you only have your jaw dropped. I am sure that **Raku** still keeps dozens of tricks that nobody discovered so far. That’s one of the fascinating things about the design of this language.

**Mohammad:** What do you suggest someone just started `The Weekly Challenge`

?

**Andrew:** Grab a task that you find simple enough. If there’s none this week, scan the previous weeks and pick one from there. Also keep in mind that the output of the problems is often not strictly defined in the task, so you may freely interpret the details and make your own choice for a simpler program. Yes, I believe that the simplicity and clarity of solutions is the main goal that the participants must seek.

**Mohammad:** Anything else you would to like to share with us?

**Andrew:** Complete the rename of the project to ‘The Weekly Challenge’ already and extend the language coverage

That brings the end of the conversation with **Andrew Shitov**. Please do let us know your view. We will come back next month with another champion.

The solutions of this week actually make me think that Raku changes my definition of what is a *straightforward solution*. All those tiny Raku bits such as `any`

or `X`

or `^$N`

are awesome even in a not fully-optimised program.

You are given an array of real numbers greater than zero. Write a script to find if there exists a triplet `(a, b, c)`

such that `1 < a + b + c < 2`

. Print 1 if you succeed otherwise 0.

So, the task is to find such three numbers from the given list so that they add up to a number between 1 and 2. Sounds as a good task for using the `combinations`

routine.

my @r = 1.2, 0.4, 0.1, 2.5; say +so 1 < any(@r.combinations(3)>>.sum) < 2;

As you see, the solution is extremely short. It creates the possible 3-element combinations from the input data and computes the sums of each. Then, we make a test `1 < any(...) < 2`

using the `any`

-junction, which allows us to avoid any explicit loops in the program. Finally, the `+so`

construct converts the result to first to a Boolean value (`so`

), and then to either 1 or 0 as the task requires.

You are given a positive integer `$N`

. Write a script to find if it can be expressed as `a ^ b`

where `a > 0`

and `b > 1`

. Print 1 if you succeed otherwise 0.

Well, some mathematics can be applied before going to the code, but let’s skip this useful step

my $N = @*ARGS[0] // 8; for 1..^$N X ^$N -> ($a, $b) { say "$N = $a^$b" if $N == $a ** $b; }

The program is quite wordy and self-explanatory, but I must mention that parentheses around loop variables are important here. Without them, you will get two pairs such as `(7 2) (7 3)`

on each iteration instead of just two integers.

The program prints all the possible solutions, and prints nothing if it could not find it.

* * *

→ GitHub repository

→ Navigation to the *Raku challenges* post series

Consider the following example:

sub f($a, *@b) { say "Head: $a"; say "Tail: @b[]"; } f(42, 43, 44);

The signature of the function has two elements: a scalar `$a`

and a slurpy array `@b`

. When you call `f`

with three parameters, the first one goes to `$a`

, and the rest land in `@b`

.

The program prints:

$ raku sub.raku Head: 42 Tail: 43 44

Let us apply the pattern from the example to a program that recursively computes the sum of the elements of an array of numbers:

multi sub rsum($head) { $head } multi sub rsum($head, *@rest) { $head + rsum(|@rest) } say rsum(10, 20, 30, 40, 50); # 150

There are no assignments here, so this program is a perfect example of programming in a functional style in Raku.

We have two versions of the `rsum`

functions here. One needs a single value, and the second one accepts additional (but required) array. While there are more than one element in the data list, the second version of the function is run. On the last iteration, a single elements remains, and thus the simpler version of the function is executed. The sum of a single element is the element itself. In the output, you get the desired sum.

* * *

Find the code of this issue on GitHub and browse for more Raku Pearls.

]]>