diff options
| author | Paulo Custodio <pauloscustodio@gmail.com> | 2023-04-09 19:01:48 +0100 |
|---|---|---|
| committer | Paulo Custodio <pauloscustodio@gmail.com> | 2023-04-09 19:01:48 +0100 |
| commit | c5c9938bcabccd143a967d74a9fc135beeee8002 (patch) | |
| tree | eb3fd8e67019cea8e1a1b30c8147478292025796 /challenge-211 | |
| parent | f03ec2c10499edf8b77ea0c3831728853c20e983 (diff) | |
| parent | 4890cd1addbde634e231ba6eb4656f7eb59085e9 (diff) | |
| download | perlweeklychallenge-club-c5c9938bcabccd143a967d74a9fc135beeee8002.tar.gz perlweeklychallenge-club-c5c9938bcabccd143a967d74a9fc135beeee8002.tar.bz2 perlweeklychallenge-club-c5c9938bcabccd143a967d74a9fc135beeee8002.zip | |
Merge remote-tracking branch 'upstream/master'
Diffstat (limited to 'challenge-211')
39 files changed, 1845 insertions, 9 deletions
diff --git a/challenge-211/0rir/raku/ch-1.raku b/challenge-211/0rir/raku/ch-1.raku new file mode 100644 index 0000000000..ef8770fe98 --- /dev/null +++ b/challenge-211/0rir/raku/ch-1.raku @@ -0,0 +1,196 @@ +#!/usr/bin/env raku +# :vim ft=raku sw=4 expandtab # 🦋 ∅∪∩∋∈∉ ≡ ≢ « » ∴ +use v6.d; +use Test; + +=begin comment +211-1: Toeplitz Matrix Submitted by: Mohammad S Anwar +Given a matrix m x n, find out if the given matrix is Toeplitz Matrix. + +A matrix is Toeplitz if every diagonal from top-left to bottom-right has +the same elements. + +Example 1 +Input: @matrix = [ [4, 3, 2, 1], + [5, 4, 3, 2], + [6, 5, 4, 3], + ] +Output: true +Example 2 +Input: @matrix = [ [1, 2, 3], + [3, 2, 1], + ] +Output: false +=end comment + +my @Test = + # shorted + [ [1,],], True, + [ [1,2,3,4,5,],], True, + [ [1,],[2,],[3,],[4,],[5],], True, + + # examples + [ [4,3,2,1], [5,4,3,2], [6,5,4,3],], True, + [ [1,2,3], [3,2,1],], False, + + # more + [ [1,1,1,1,], [1,1,1,1,], [1,1,1,1,], [1,1,1,1,],], True, + [ [1,2],[2,1],], True, + [ [1,2,3,], [4,1,2,], [5,4,1,],], True, + [ [0,1,2],[1,0,1],[2,1,0],[3,2,1],[4,3,2],], True, + + [ [9,9,], + [9,0,],], False, + + [ [0,9,], + [9,9,],], False, + + [ [0,1,9], + [1,0,1], + [9,1,0],], True, + + [ [9,1,9], + [1,0,1], + [9,1,0],], False, + + [ [0,9,9], + [1,0,1], + [9,1,0],], False, + + [ [0,1,9], + [9,0,1], + [9,1,0],], False, + + [ [0,1,9], + [1,9,1], + [9,1,0],], False, + + [ [0,1,9], + [1,0,9], + [9,1,0],], False, + + [ [0,1,9], + [1,0,1], + [9,9,0],], False, + + [ [0,1,9], + [1,0,1], + [9,1,9],], False, + + [ [0,2,], + [1,0,], + [2,1,], + [0,2,],], True, + + [ [0,1,5,6,], + [1,0,1,5,], + [2,1,0,1,], + [6,2,1,0,],], True, + + [ [0,1,2,6,], + [1,0,1,2,], + [2,1,0,1,], + [6,2,1,0,],], True, + + [ [0,1,5,6,7,], + [1,0,1,5,6,], + [2,1,0,1,5,], + [0,2,1,0,1,],], True, + + [ [0,1,5,6,7,], + [1,0,1,5,6,], + [2,1,0,1,5,], + [0,2,1,0,1,],], True, +; + +my @Dead = + [ ], + [ [],], + [ [1,],[],], + [ [1,],[1,2],], + [ [4,3,2,1], [5,4,3,2], [5,4,3],], +; + +plan @Test + @Dead; + + +sub is-toeplitz( @a -->Bool){ + + invalid( @a); + + my ($cols, $rows) = @a[0].end, @a.end; + + return True if $cols == 0 or $rows == 0; # very short diagonals + + my $o = [ $rows-1, 0]; + + loop { + return False unless $o.&diag; + $o.&next-diag; + last if $o.&last-diag; + } + return True; + + # --- not reached ---- + + constant R = 0; + constant C = 1; + + sub val( $d -->Any){ @a[ $d[R]][ $d[C]] } + + sub next-diag( $d is rw -->Array){ # alter dyad to index next diag origin + when $d[R] > 0 { --$d[R]; $d } + when $d[R] == 0 { ++$d[C]; $d } + die 'not reached ( stupid programmer either way)'; + } + + sub last-diag( $d -->Bool){ $d[R] == 0 and $d[C] == $cols} + + sub diag( $d -->Bool){ + my $ref = $d.&val; + my ($R, $C) = 1 + $d[R], 1 + $d[C]; + while $R ≤ $rows and $C ≤ $cols { + return False if $ref ≠ @a[$R++][$C++]; + } + return True; + } + sub invalid( @a -->Nil){ + when @a ~~ Empty { die "Empty" } + when @a.any ~~ Empty { die "Empty elem" } + with @a[1..^@a].first( {.end !~~ @a[0].end} ) { + die "Misshapened"; } + return; + } +} + +for @Dead -> @in { + dies-ok { is-toeplitz( @in )}, + "Died-ok: Empty, Empty elem, or misshapened"; +} +for @Test -> @in, $exp { + lives-ok { is-toeplitz( @in )}, + "Lives-ok: Empty, Empty elem, or misshapened"; + is is-toeplitz(@in), $exp, "$exp <- @in.raku()"; +} +done-testing; + + +my @matrix = [ [0,1,5,6,7,], + [1,0,1,5,6,], + [2,1,0,1,5,], + [0,2,1,0,1,],]; + +sub matrix-say( @m is copy ) { + for @matrix -> $row is rw { + $row = $row.join( ","); + } + print "\nInput @matrix = [ ["; + print @matrix.join: "],\n ["; + print "],\n ]\n"; +} + +matrix-say( @matrix); +say "Output: ", is-toeplitz( @matrix); + +exit; + diff --git a/challenge-211/0rir/raku/ch-2.raku b/challenge-211/0rir/raku/ch-2.raku new file mode 100644 index 0000000000..3828fa95c6 --- /dev/null +++ b/challenge-211/0rir/raku/ch-2.raku @@ -0,0 +1,91 @@ +#!/usr/bin/env raku +# :vim ft=raku sw=4 expandtab # 🦋 ∅∪∩∋∈∉ ≡ ≢ « » ∴ +use v6.d; +use Test; + +=begin comment +211-2: Split Same Average Submitted by: Mohammad S Anwar +Given an array of integers, find out if the array can be split into two +separate arrays whose averages are the same. + +Example 1: +Input: @nums = (1, 2, 3, 4, 5, 6, 7, 8) +Output: true +We can split the given array into (1, 4, 5, 8) and (2, 3, 6, 7). +The average of the two arrays are the same i.e. 4.5. + +Example 2: +Input: @list = (1, 3) +Output: false +=end comment + +my @Test = + # shorts -- atomic + [ ], False, + [ 1], False, + # given examples + [ 1,3], False, + [ 2,3,6,7, 1,4,5,8], True, + # more + [ 11 xx 111], True, + [ 0,0,0,0,0], True, + [ 1,1], True, + [ 1,2], False, + [ 1,2,4], False, + [ 2,2,3], False, + [ 1,-1], False, + [ 1,14,15], False, + [ 1,14, 0,15], True, + [ 0,0,1,14,15], False, + [ 0,1,14, 0,0,15], True, + [ 1,2,3,12,13,14,15], False, + [ 0,7, 1,2,3,4,5,6], True, + [ 0,1,1,2,3,4,5,6,7], False, + [ 1,4, 2,3], True, + [ 2, 0,1,3,4], True, + [ 1,4,5,7, 0,2,3,6,8], True, + [ -2, -1,-1,0], True, + [ -3,-2,-1,1], False, + [ -3…0], True, + [ -3…1], True, + [ -1,0,2,6,7, 1,1,3,4,5], True, + [ -1,-1,2,6,7, 0,1,3,4,5], True, + [ -1,1,2,3,4,5,6,7], False, + [ -10…10], True, + [ -9…10], True, + [ 1…12], True, + [ 0…12], True, + [ -2…1], True, + [ -4…4], True, +; + +# return True if so 'subset.elems × other.sum == subset.sum × other.elems' +# is found, else False. +multi same-average-parts2( @in where *.elems ≤ 1 -->Bool ){ False } +multi same-average-parts2( @in -->Bool){ + + my Int $total = [+] @in; + + my $prev; + for 1..(@in.elems div 2) -> $a-elems { + for @in.combinations( $a-elems).sort -> $a { + my $b-val = $a-elems × ($total - [+] $a); + + if $b-val == ([+] $a) × ( @in.elems - $a-elems) { + return True; + } } } + return False; +} + +plan @Test/2; + +for @Test -> @t, $exp { + is same-average-parts2( @t), $exp, "$exp <- @t[]"; +} +done-testing; + +my $ints = @Test[*-2]; +say "\nInput: \$ints = $ints[]" + ,"\nOutput: &same-average-parts2($ints)"; + +exit; diff --git a/challenge-211/carlos-oliveira/perl/ch-1.pl b/challenge-211/carlos-oliveira/perl/ch-1.pl new file mode 100644 index 0000000000..bfd6351111 --- /dev/null +++ b/challenge-211/carlos-oliveira/perl/ch-1.pl @@ -0,0 +1,27 @@ +use strict; +use warnings; +use v5.36; + +use Test::More; +use List::Util qw(uniq); + +sub is_toeplitz_matrix (@matrix) { + my $cols = $matrix[0]->@*; + for my $i (0..$#matrix) { + my @diagonal = uniq map { $i < $cols ? $_->[$i++] : () } @matrix; + return 0 unless @diagonal == 1; + } + return 1; +} + +is is_toeplitz_matrix( + [4, 3, 2, 1], + [5, 4, 3, 2], + [6, 5, 4, 3] +), 1; +is is_toeplitz_matrix( + [1, 2, 3], + [3, 2, 1] +), 0; + +done_testing; diff --git a/challenge-211/carlos-oliveira/perl/ch-2.pl b/challenge-211/carlos-oliveira/perl/ch-2.pl new file mode 100644 index 0000000000..421b8e94d7 --- /dev/null +++ b/challenge-211/carlos-oliveira/perl/ch-2.pl @@ -0,0 +1,19 @@ +use strict; +use warnings; +use v5.36; + +use Test::More; +use Algorithm::Combinatorics qw(partitions); +use List::Util qw(any sum uniqnum); +use builtin qw(true false); + +sub can_be_split_with_same_average (@array) { + return any { $_->@* == 1 } + map { [ uniqnum map sum($_->@*) / $_->@*, $_->@* ] } + partitions \@array, 2; +} + +is can_be_split_with_same_average(1, 2, 3, 4, 5, 6, 7, 8), true; +is can_be_split_with_same_average(1, 3), false; + +done_testing; diff --git a/challenge-211/e-choroba/perl/ch-1.pl b/challenge-211/e-choroba/perl/ch-1.pl new file mode 100755 index 0000000000..90ae514e7b --- /dev/null +++ b/challenge-211/e-choroba/perl/ch-1.pl @@ -0,0 +1,47 @@ +#! /usr/bin/perl +use warnings; +use strict; +use experimental qw( signatures ); + +sub toeplitz_matrix($m) { + my $x = 0; + my $y = $#$m; + while ($x <= $#{ $m->[0] }) { + my ($u, $v) = ($x, $y); + while (++$u <= $#{ $m->[0] } && ++$v <= $#$m) { + return if $m->[$v][$u] != $m->[$y][$x]; + } + } continue { + if ($y) { + --$y; + } else { + ++$x; + } + } + return 1 +} + +use Test::More tests => 4; + +ok toeplitz_matrix([ [4, 3, 2, 1], + [5, 4, 3, 2], + [6, 5, 4, 3], + ]), 'Example 1'; + +ok ! toeplitz_matrix([ [1, 2, 3], + [3, 2, 1], + ]), 'Example 2'; + +ok toeplitz_matrix([[1]]), '1x1'; +ok toeplitz_matrix([[1,2,3,4,5,6,7], + [8,1,2,3,4,5,6], + [9,8,1,2,3,4,5], + [10,9,8,1,2,3,4], + [11,10,9,8,1,2,3], + [12,11,10,9,8,1,2], + [13,12,11,10,9,8,1], + [14,13,12,11,10,9,8], + [15,14,13,12,11,10,9], + [16,15,14,13,12,11,10], + [17,16,15,14,13,12,11], + ]), 'Larger'; diff --git a/challenge-211/e-choroba/perl/ch-2.pl b/challenge-211/e-choroba/perl/ch-2.pl new file mode 100755 index 0000000000..02942855f9 --- /dev/null +++ b/challenge-211/e-choroba/perl/ch-2.pl @@ -0,0 +1,72 @@ +#! /usr/bin/perl +use warnings; +use strict; +use experimental qw( signatures ); + +use List::Util qw{ sum }; + +sub split_same_average_brute_force(@list) { + my $avg = sum(@list) / @list; + my @mask = (0) x @list; + $mask[-1] = 1; + while (1) { + my $s = sum(@list[grep $mask[$_], 0 .. $#mask]); + return 1 if abs($s / (grep $_, @mask) - $avg) < 1e-9; + + my $pos = $#mask; + while ($mask[$pos]) { + $mask[$pos] = 0; + return if --$pos < 1; + } + $mask[$pos] = 1; + } + +} + +sub split_same_average(@list) { + my $sum = sum(@list); + my $avg = $sum / @list; + my $max_length = (@list + 1) / 2; + --$max_length if $max_length >= @list - 1; + + my %possible; # {sum}{length} + $possible{0}{0} = 1; + for my $e (@list) { + # Sort is needed so we don't process the added sum again in + # the same step. + for my $s (sort { $b <=> $a } keys %possible) { + for my $length (keys %{ $possible{$s} }) { + next if $length == @list - 1; + + $possible{ $s + $e }{ $length + 1 } = 1; + return 1 if abs(($s + $e) / ($length+1) - $avg) < 1e-9; + } + } + } + return +} + +use Test::More; + +ok split_same_average(1, 2, 3, 4, 5, 6, 7, 8), 'Example 1'; +ok ! split_same_average(1, 3), 'Example 2'; + +ok split_same_average(-2, 0, 2), 'Avg 0'; +ok split_same_average(1, 5, 5, 1), 'Duplicates'; + +for (1 .. 200) { + my @list = map int rand 20, 1 .. 2 + rand 10; + is split_same_average(@list), split_same_average_brute_force(@list), + "same @list"; +} + +my @l = map int rand 50, 1 .. 12; +is split_same_average(@l), split_same_average_brute_force(@l), + "same @l"; +done_testing(); + +use Benchmark qw{ cmpthese }; +cmpthese(-3, { + brute_force => sub { split_same_average_brute_force(@l) }, + fast => sub { split_same_average(@l) }, +}); diff --git a/challenge-211/jeanluc2020/blog-1.txt b/challenge-211/jeanluc2020/blog-1.txt new file mode 100644 index 0000000000..0f0f93f599 --- /dev/null +++ b/challenge-211/jeanluc2020/blog-1.txt @@ -0,0 +1 @@ +http://gott-gehabt.de/800_wer_wir_sind/thomas/Homepage/Computer/perl/theweeklychallenge-211-1.html diff --git a/challenge-211/jeanluc2020/blog-2.txt b/challenge-211/jeanluc2020/blog-2.txt new file mode 100644 index 0000000000..bd76722861 --- /dev/null +++ b/challenge-211/jeanluc2020/blog-2.txt @@ -0,0 +1 @@ +http://gott-gehabt.de/800_wer_wir_sind/thomas/Homepage/Computer/perl/theweeklychallenge-211-2.html diff --git a/challenge-211/jeanluc2020/perl/ch-1.pl b/challenge-211/jeanluc2020/perl/ch-1.pl new file mode 100755 index 0000000000..c68d360ce9 --- /dev/null +++ b/challenge-211/jeanluc2020/perl/ch-1.pl @@ -0,0 +1,79 @@ +#!/usr/bin/perl +# https://theweeklychallenge.org/blog/perl-weekly-challenge-211/#TASK1 +# +# Task 1: Toeplitz Matrix +# ======================= +# +# You are given a matrix m x n. +# +# Write a script to find out if the given matrix is Toeplitz Matrix. +# +## A matrix is Toeplitz if every diagonal from top-left to bottom-right has the +## same elements. +# +## Example 1 +## +## Input: @matrix = [ [4, 3, 2, 1], +## [5, 4, 3, 2], +## [6, 5, 4, 3], +## ] +## Output: true +# +## Example 2 +## +## Input: @matrix = [ [1, 2, 3], +## [3, 2, 1], +## ] +## Output: false +# +############################################################ +## +## discussion +## +############################################################ +# +# We just need to walk all diagonals and check if all numbers are +# the same. But actually it's easier to walk the matrix and check +# whether the element to the right bottom of the current one differs +# from the current one. When we do that everywhere we can know +# whether all diagonals have the same number everywhere as well, +# so let's do that. + +toeplitz([ [4, 3, 2, 1], + [5, 4, 3, 2], + [6, 5, 4, 3] ]); +toeplitz([ [1, 2, 3], + [3, 2, 1] ]); + +sub toeplitz { + my $matrix = shift; + die "Not a matrix" unless is_matrix($matrix); + # get the dimensions of the matrix + my $lines = scalar(@$matrix); + my $columns = scalar(@{$matrix->[0]}); + # for each line and column except the last one, compare the element + # at that position and the one on the right bottom of it + foreach my $i (0..$lines-2) { + foreach my $j (0..$columns-2) { + my $this_element = $matrix->[$i]->[$j]; + my $next_diagonal_element = $matrix->[$i+1]->[$j+1]; + if ($this_element != $next_diagonal_element) { + print "Output: false\n"; + return; + } + } + } + print "Output: true\n"; +} + +# helper function to check if we actually have a matrix +sub is_matrix { + my $matrix = shift; + return 0 unless ref($matrix) eq "ARRAY"; + my $columns = scalar(@{$matrix->[0]}); + foreach my $line (@$matrix) { + return 0 unless scalar(@$line) == $columns; + } + return 1; +} + diff --git a/challenge-211/jeanluc2020/perl/ch-2.pl b/challenge-211/jeanluc2020/perl/ch-2.pl new file mode 100755 index 0000000000..10407b7a85 --- /dev/null +++ b/challenge-211/jeanluc2020/perl/ch-2.pl @@ -0,0 +1,97 @@ +#!/usr/bin/perl +# https://theweeklychallenge.org/blog/perl-weekly-challenge-211/#TASK2 +# +# Task 2: Split Same Average +# ========================== +# +# You are given an array of integers. +# +# Write a script to find out if the given can be split into two separate arrays whose average are the same. +# +## Example 1: +## +## Input: @nums = (1, 2, 3, 4, 5, 6, 7, 8) +## Output: true +## +## We can split the given array into (1, 4, 5, 8) and (2, 3, 6, 7). +## The average of the two arrays are the same i.e. 4.5. +# +## Example 2: +## +## Input: @list = (1, 3) +## Output: false +# +############################################################ +## +## discussion +## +############################################################ +# +# This is basically a problem on how to create all possible +# combinations and checking if any of these allows for the +# same average + +use strict; +use warnings; +use List::Util qw(sum); + +split_same_average(1, 2, 3, 4, 5, 6, 7, 8); +split_same_average(1, 3); + +sub split_same_average { + my @list = @_; + print "Input: (" . join(", ", @list) . ")\n"; + if(has_matching_split([@list], [], [])) { + print "Output: true\n"; + } else { + print "Output: false\n"; + } +} + +# check if the rest of the current list, with two partially +# filled lists from the previous elements, can still be turned +# into two lists that have the same average +# so we create all possible combinations step by step, if we have +# found one we check if it has lead us to two lists of the same +# average, and otherwise return a non-true value (which will lead +# to the next recursive call) +sub has_matching_split { + my ($rest, $list1, $list2) = @_; + if(@$rest) { + # we still have some elements to distribute among the two + # lists, so we get the first element of this remainder + my $first = shift @$rest; + # if by adding this to the first partial list we can achieve + # a combination where both lists have the same average, we can + # finish searching and return 1 + if(has_matching_split([@$rest], [@$list1, $first], [@$list2])) { + return 1; + } + # same is true if we can achieve a good combination by adding the + # element to the second partial list + if(has_matching_split([@$rest], [@$list1], [@$list2, $first])) { + return 1; + } + # if we didn't succeed either way, we can't find any matching combination + # that leads to two arrays with the same average, so we return 0 + return 0; + } else { + # we have distributed all elements to the two lists, so if both + # lists are non-empty and share the same average we have found a + # solution + if(@$list1 && @$list2 && average(@$list1) == average(@$list2)) { + return 1; + } + } + return 0; +} + +# of course we need a helper function to calculate the average of all +# elements of a list +sub average { + my @list = @_; + my $count = @list; + return undef unless $count; + my $sum = sum @list; + return $sum / $count; +} diff --git a/challenge-211/mark-anderson/raku/ch-2.raku b/challenge-211/mark-anderson/raku/ch-2.raku index 255ada41f4..9b88288ee3 100644 --- a/challenge-211/mark-anderson/raku/ch-2.raku +++ b/challenge-211/mark-anderson/raku/ch-2.raku @@ -1,6 +1,11 @@ #!/usr/bin/env raku use Test; +# This is a do-over after reading other solutions. +# Jorg Sommrey and W. Luis Mochan explained that if one subset's average +# equals the average of the whole list then the other subset will have +# the same average. + ok split-same-avg(1,2,3,4,5,6,7,8); # [1 8] [2 3 4 5 6 7] nok split-same-avg(1,3); ok split-same-avg(3,3,5,5,5,2,2,1); # [2 3 3 5] [1 2 5 5] @@ -8,14 +13,11 @@ nok split-same-avg(5,5,5,2,2,1); sub split-same-avg(*@nums) { - for (^@nums).combinations(1..@nums.elems div 2) -> @a is copy - { - my @b = (^@nums (-) @a).keys; + my $avg = @nums.sum / @nums.elems; - @a = @nums[@a]; - @b = @nums[@b]; - - return True if @a.sum / @a.elems == @b.sum / @b.elems + for (^@nums).combinations(1..@nums.elems div 2) -> @a + { + return True if @nums[@a].sum / @nums[@a].elems == $avg } return False diff --git a/challenge-211/peter-campbell-smith/blog.txt b/challenge-211/peter-campbell-smith/blog.txt new file mode 100644 index 0000000000..8ca8f03329 --- /dev/null +++ b/challenge-211/peter-campbell-smith/blog.txt @@ -0,0 +1 @@ +http://ccgi.campbellsmiths.force9.co.uk/challenge/211 diff --git a/challenge-211/peter-campbell-smith/perl/ch-1.pl b/challenge-211/peter-campbell-smith/perl/ch-1.pl new file mode 100755 index 0000000000..bd20e4b8ce --- /dev/null +++ b/challenge-211/peter-campbell-smith/perl/ch-1.pl @@ -0,0 +1,79 @@ +#!/usr/bin/perl + +use v5.16; # The Weekly Challenge - 2023-04-03 +use utf8; # Week 211 task 1 - Toeplitz matrix +use strict; # Peter Campbell Smith +use warnings; # Blog: http://ccgi.campbellsmiths.force9.co.uk/challenge + +toeplitz_matrix( [[4, 3, 2, 1], + [5, 4, 3, 2], + [6, 5, 4, 3]] ); + +toeplitz_matrix( [[4, 3, 2, 1], + [5, 4, 3, 2], + [6, 5, 4, 7]] ); + +toeplitz_matrix( [[37.1, 114, 0, -23.65, 5, 3], + [-40, 37.1, 114, 0, -23.65, 5], + [-19, -40, 37.1, 114, 0, -23.65], + [3, -19, -40, 37.1, 114, 0], + [55, 3, -19, -40, 37.1, 114], + [0, 55, 3, -19, -40, 37.1], + [999, 0, 55, 3, -19, -40]] ); + +toeplitz_matrix( [[6, 0, 0, 0, 6], + [0, 0, 6, 0, 0], + [6, 0, 0, 0, 6]] ); + +sub toeplitz_matrix { + + my($m, $r, $c, $x, $good); + + $m = $_[0]; + + # loop over rows and then columns + ROW: for $r (1 .. scalar @$m - 1) { |
