Vowelled Matrix with Raku

[64] Published 26. March 2020.

This is my response to the Perl Weekly Challenge #53.

Challenge #53.1: Rotate Matrix

Write a script to rotate the following matrix by given 90/180/270 degrees clockwise. [ 1, 2, 3 ] [ 4, 5, 6 ] [ 7, 8, 9 ] For example, if you rotate by 90 degrees then expected result should be like below [ 7, 4, 1 ] [ 8, 5, 2 ] [ 9, 6, 3 ]



In my FC Matrix with Raku article (in response to Challenge #11.2), I started with the «Math::Matrix» module, and then did it manually with a shaped array. This time I'll do it with regular arrays. Or rather, an array of arrays.

subset Degree where * == any(90, 180, 270); # [1] unit sub MAIN (Degree $degree is copy = 90, :$verbose); # [2] my @matrix = ((1,2,3), (4,5,6), (7,8,9)); # [3] while $degree # [4] { @matrix = rot90(@matrix); # [4a] $degree -= 90; # [4b] } say @matrix.raku; # [5]

File: matrix-rotation (partial)

[1] A custom type with subset for the legal degrees. Note the absence of the typical of Int , and the use of a list of values with an any junction instead.

[2] Note is copy on the argument, so that we can change it.

[3] The matrix given in the challenge, specified as a list of lists.

[4] Rotate the matrix 90 degrees at a time, until we reach the correct one.

[5] Show the new matrix.

sub rot90 (@matrix) # [6] { my @new; # [7] for ^@matrix[0].elems -> $col # [8] { my @row; # [9] for ^@matrix.elems -> $row # [10] { say ":c ", @matrix[$row][$col] if $verbose; @row.push(@matrix[$row][$col]); # [11] } say ":r ", @row.reverse if $verbose; @new.push(@row.reverse.list); # [12] } return @new; # [13] }

File: matrix-rotation (the rest)

[6] This one does the rotation, 90 degrees to the left.

[7] The new matrix goes here.

[8] Iterate over the columns,

[9] • We collect the new row here.

[10] • Iterate over the rows,

[11] • • get the cell value and add it to the new row.

[12] • Add the new row, reversed (as the for loop does it the wrong way). Note the list coercer, as reverse gives a Sequence.

[13] Return the new array.

Running it:

$ raku matrix-rotation [(7, 4, 1), (8, 5, 2), (9, 6, 3)] $ raku matrix-rotation 90 [(7, 4, 1), (8, 5, 2), (9, 6, 3)] $ raku matrix-rotation 180 [(9, 8, 7), (6, 5, 4), (3, 2, 1)] $ raku matrix-rotation 270 [(3, 6, 9), (2, 5, 8), (1, 4, 7)]

The whould check that the rotation roundtrips. Add «360» degrees like this:

subset Degree where * == any(90, 180, 270 , 360 );

File: matrix-rotation (changes only)

Running it:

$ raku matrix-rotation 360 [(1, 2, 3), (4, 5, 6), (7, 8, 9)]

Looking good.

Math::Matrix

We can use the Math::Matrix module, even if it doesn't support rotation out of the box. The program is much simpler this time:

use Math::Matrix; subset Degree where * == any(90, 180, 270); unit sub MAIN (Degree $degree is copy = 90, :$verbose); my $matrix = Math::Matrix.new(((1,2,3), (4,5,6), (7,8,9))); # [1] say "$matrix

" if $verbose; while $degre { $matrix = Math::Matrix.new($matrix.list-columns>>.reverse); # [2] $degree -= 90; } say $matrix;

File: matrix-rotation-module

[1] Set up the initial matrix.

[2] Rotate 90 degrees at a time. The «list-columns» method gives the new rows, in the wrong order (as in the first program). We apply reverse on each row (with >>. ) in one go to fix that.

Running it:

$ raku matrix-rotation-module 7 4 1 8 5 2 9 6 3 $ raku matrix-rotation-module 180 9 8 7 6 5 4 3 2 1 $ raku matrix-rotation-module 270 3 6 9 2 5 8 1 4 7

Challenge #53.2: Vowel Strings

Write a script to accept an integer 1 <= N <= 5 that would print all possible strings of size N formed by using only vowels (a, e, i, o, u). The string should follow the following rules: ‘a’ can only be followed by ‘e’ and ‘i’. ‘e’ can only be followed by ‘i’. ‘i’ can only be followed by ‘a’, ‘e’, ‘o’, and ‘u’. ‘o’ can only be followed by ‘a’ and ‘u’. ‘u’ can only be followed by ‘o’ and ‘e’. For example, if the given integer N = 2 then script should print the following strings: ae ai ei ia io iu ie oa ou uo ue



A recursive procedure seems like a good idea.

unit sub MAIN (Int $n where 1 <= $n <= 5, :$verbose); # [1] my @start = <a e i o u>; # [2] my %next; # [3] %next<a> = <e i>; # [3a] %next<e> = <i>; # [3e] %next<i> = <a e o u>; # [3i] %next<o> = <a u>; # [3o] %next<u> = <o e>; # [3u] say ": ", %next if $verbose; say ": ", %next.raku if $verbose; do-it($_) for @start; # [4] sub do-it ($string) # [5] { if $string.chars == $n # [6] { say $string; # [6a] } else # [7] { my $last = $string.substr(*-1); # [8] say ": $string -> { @(%next{$last}).join("|") }" if $verbose; do-it("$string$_") for @(%next{$last}); # [9] } }

File: vowel-string

[1] Legal values: 1, 2, 3, 4 or 5.

[2] We start with these letters.

[3] A list of legal letters following the current one.

[4] Iterate over the starting letters.

[5] The procedure is recursive.

[6] If we have reached the requested string length, print the string (6a) (and return).

[7] If not,

[8] • get the last character in the current string. *-1 gives the index of the last character when used in substr .

[9] • add the letters following the last character, and call ourselves with the new string recursively.

Running it:

$ raku vowel-string 1 a e i o u $ raku vowel-string 2 ae ai ei ia ie io iu oa ou uo ue $ raku vowel-string 3 aei aia aie aio aiu eia eie eio eiu iae iai iei ioa iou iuo iue oae oai ouo oue uoa uou uei $ raku vowel-string 4 aeia aeie aeio aeiu aiae aiai aiei aioa aiou aiuo aiue eiae eiai eiei eioa eiou eiuo eiue iaei iaia iaie iaio iaiu ieia ieie ieio ieiu ioae ioai iouo ioue iuoa iuou iuei oaei oaia oaie oaio oaiu ouoa ouou ouei uoae uoai uouo uoue ueia ueie ueio ueiu $ raku vowel-string 5 aeiae aeiai aeiei aeioa aeiou aeiuo aeiue aiaei aiaia aiaie aiaio aiaiu aieia aieie aieio aieiu aioae aioai aiouo aioue aiuoa aiuou aiuei eiaei eiaia eiaie eiaio eiaiu eieia eieie eieio eieiu eioae eioai eiouo eioue eiuoa eiuou eiuei iaeia iaeie iaeio iaeiu iaiae iaiai iaiei iaioa iaiou iaiuo iaiue ieiae ieiai ieiei ieioa ieiou ieiuo ieiue ioaei ioaia ioaie ioaio ioaiu iouoa iouou iouei iuoae iuoai iuouo iuoue iueia iueie iueio iueiu oaeia oaeie oaeio oaeiu oaiae oaiai oaiei oaioa oaiou oaiuo oaiue ouoae ouoai ououo ououe oueia oueie oueio oueiu uoaei uoaia uoaie uoaio uoaiu uouoa uouou uouei ueiae ueiai ueiei ueioa ueiou ueiuo ueiue

Looking good.

And that's it.