diff options
| author | Mohammad Sajid Anwar <Mohammad.Anwar@yahoo.com> | 2024-02-21 09:09:21 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-02-21 09:09:21 +0000 |
| commit | ca0b0155464c85ed3a2a2f3a35d885fc2db6480d (patch) | |
| tree | 429b642941c84dc992b38aa77d0fd977795dd1d9 | |
| parent | 1036bfd73a5af401f2fb49d91cb22d62f9a782eb (diff) | |
| parent | 0bc762c27d1e12169f8c2ce41e5feb8902cdc8af (diff) | |
| download | perlweeklychallenge-club-ca0b0155464c85ed3a2a2f3a35d885fc2db6480d.tar.gz perlweeklychallenge-club-ca0b0155464c85ed3a2a2f3a35d885fc2db6480d.tar.bz2 perlweeklychallenge-club-ca0b0155464c85ed3a2a2f3a35d885fc2db6480d.zip | |
Merge pull request #9620 from PerlMonk-Athanasius/branch-for-challenge-257
Perl & Raku solutions to Tasks 1 & 2 for Week 257
| -rw-r--r-- | challenge-257/athanasius/perl/ch-1.pl | 177 | ||||
| -rw-r--r-- | challenge-257/athanasius/perl/ch-2.pl | 410 | ||||
| -rw-r--r-- | challenge-257/athanasius/raku/ch-1.raku | 178 | ||||
| -rw-r--r-- | challenge-257/athanasius/raku/ch-2.raku | 410 |
4 files changed, 1175 insertions, 0 deletions
diff --git a/challenge-257/athanasius/perl/ch-1.pl b/challenge-257/athanasius/perl/ch-1.pl new file mode 100644 index 0000000000..9be329e6ae --- /dev/null +++ b/challenge-257/athanasius/perl/ch-1.pl @@ -0,0 +1,177 @@ +#!perl + +################################################################################ +=comment + +Perl Weekly Challenge 257 +========================= + +TASK #1 +------- +*Smaller than Current* + +Submitted by: Mohammad Sajid Anwar + +You are given an array of integers, @ints. + +Write a script to find out how many integers are smaller than current i.e. +foreach ints[i], count ints[j] < ints[i] where i != j. + +Example 1 + + Input: @ints = (5, 2, 1, 6) + Output: (2, 1, 0, 3) + + For $ints[0] = 5, there are two integers (2,1) smaller than 5. + For $ints[1] = 2, there is one integer (1) smaller than 2. + For $ints[2] = 1, there is none integer smaller than 1. + For $ints[3] = 6, there are three integers (5,2,1) smaller than 6. + +Example 2 + + Input: @ints = (1, 2, 0, 3) + Output: (1, 2, 0, 3) + +Example 3 + + Input: @ints = (0, 1) + Output: (0, 1) + +Example 4 + + Input: @ints = (9, 4, 9, 2) + Output: (2, 1, 2, 0) + +=cut +################################################################################ + +#--------------------------------------# +# Copyright © 2024 PerlMonk Athanasius # +#--------------------------------------# + +#=============================================================================== +=comment + +Interface +--------- +If no command-line arguments are given, the test suite is run. + +=cut +#=============================================================================== + +use v5.32.1; # Enables strictures +use warnings; +use Const::Fast; +use Regexp::Common qw( number ); +use Test::More; + +const my $USAGE => <<END; +Usage: + perl $0 [<ints> ...] + perl $0 + + [<ints> ...] A non-empty array of integers +END + +#------------------------------------------------------------------------------- +BEGIN +#------------------------------------------------------------------------------- +{ + $| = 1; + print "\nChallenge 257, Task #1: Smaller than Current (Perl)\n\n"; +} + +#=============================================================================== +MAIN: +#=============================================================================== +{ + if (scalar @ARGV == 0) + { + run_tests(); + } + else + { + my @ints = @ARGV; + + for (@ints) + { + / ^ $RE{num}{int} $ /x or error( qq["$_" is not a valid integer] ); + } + + printf "Input: \@ints = (%s)\n", join ', ', @ints; + + my $counts = count_smaller_than_current( \@ints ); + + printf "Output: (%s)\n", join ', ', @$counts; + } +} + +#------------------------------------------------------------------------------- +sub count_smaller_than_current +#------------------------------------------------------------------------------- +{ + my ($ints) = @_; + my @counts; + + for my $i (0 .. $#$ints) + { + my $count = 0; + + for my $j (0 .. $#$ints) + { + next if $i == $j; + + ++$count if $ints->[ $j ] < $ints->[ $i ]; + } + + push @counts, $count; + } + + return \@counts; +} + +#------------------------------------------------------------------------------- +sub run_tests +#------------------------------------------------------------------------------- +{ + print "Running the test suite\n"; + + while (my $line = <DATA>) + { + chomp $line; + + my ($test_name, $int_str, $exp_str) = split / \| /x, $line; + + for ($test_name, $int_str, $exp_str) + { + s/ ^ \s+ //x; + s/ \s+ $ //x; + } + + my @ints = split / \s+ /x, $int_str; + my @exp = split / \s+ /x, $exp_str; + my $counts = count_smaller_than_current( \@ints ); + + is_deeply $counts, \@exp, $test_name; + } + + done_testing; +} + +#------------------------------------------------------------------------------- +sub error +#------------------------------------------------------------------------------- +{ + my ($message) = @_; + + die "ERROR: $message\n$USAGE"; +} + +################################################################################ + +__DATA__ +Example 1| 5 2 1 6|2 1 0 3 +Example 2| 1 2 0 3|1 2 0 3 +Example 3| 0 1 |0 1 +Example 4| 9 4 9 2|2 1 2 0 +Negatives|-2 -2 -1 |0 0 2 diff --git a/challenge-257/athanasius/perl/ch-2.pl b/challenge-257/athanasius/perl/ch-2.pl new file mode 100644 index 0000000000..bb16d5aaf9 --- /dev/null +++ b/challenge-257/athanasius/perl/ch-2.pl @@ -0,0 +1,410 @@ +#!perl + +################################################################################ +=comment + +Perl Weekly Challenge 257 +========================= + +TASK #2 +------- +*Reduced Row Echelon* + +Submitted by: Ali Moradi + +Given a matrix M, check whether the matrix is in reduced row echelon form. + +A matrix must have the following properties to be in reduced row echelon form: + + 1. If a row does not consist entirely of zeros, then the first + nonzero number in the row is a 1. We call this the leading 1. + 2. If there are any rows that consist entirely of zeros, then + they are grouped together at the bottom of the matrix. + 3. In any two successive rows that do not consist entirely of zeros, + the leading 1 in the lower row occurs farther to the right than + the leading 1 in the higher row. + 4. Each column that contains a leading 1 has zeros everywhere else + in that column. + +For example: + + [ + [1,0,0,1], + [0,1,0,2], + [0,0,1,3] + ] + +The above matrix is in reduced row echelon form since the first nonzero number +in each row is a 1, leading 1s in each successive row are farther to the right, +and above and below each leading 1 there are only zeros. + +For more information check out this wikipedia +[https://en.wikipedia.org/wiki/Row_echelon_form|article]. + +Example 1 + + Input: $M = [ + [1, 1, 0], + [0, 1, 0], + [0, 0, 0] + ] + Output: 0 + +Example 2 + + Input: $M = [ + [0, 1,-2, 0, 1], + [0, 0, 0, 1, 3], + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0] + ] + Output: 1 + +Example 3 + + Input: $M = [ + [1, 0, 0, 4], + [0, 1, 0, 7], + [0, 0, 1,-1] + ] + Output: 1 + +Example 4 + + Input: $M = [ + [0, 1,-2, 0, 1], + [0, 0, 0, 0, 0], + [0, 0, 0, 1, 3], + [0, 0, 0, 0, 0] + ] + Output: 0 + +Example 5 + + Input: $M = [ + [0, 1, 0], + [1, 0, 0], + [0, 0, 0] + ] + Output: 0 + +Example 6 + + Input: $M = [ + [4, 0, 0, 0], + [0, 1, 0, 7], + [0, 0, 1,-1] + ] + Output: 0 + +=cut +################################################################################ + +#--------------------------------------# +# Copyright © 2024 PerlMonk Athanasius # +#--------------------------------------# + +#=============================================================================== +=comment + +Interface +--------- +1. If no command-line arguments are given, the test suite is run. Otherwise: +2. The input matrix M is entered on the command-line as a non-empty list of + strings (the matrix rows) containing elements separated by whitespace. For + example, the matrix: + + [ 1 1 0 ] + [ 0 1 0 ] + [ 0 0 0 ] + + is entered as: >raku ch-2.raku "1 1 0" "0 1 0" "0 0 1" + +Assumptions +----------- +1. The input matrix M is an integer matrix. +2. M is not an empty matrix. + +Note +---- +Matrix-handling code is adapted from the solution to Task 2 for Week 248. + +=cut +#=============================================================================== + +use v5.32.1; # Enables strictures +use warnings; +use Const::Fast; +use Regexp::Common qw( number ); +use Test::More; +use enum qw( AllZeros LeadingOne Other ); + +const my $USAGE => <<END; +Usage: + perl $0 [<M> ...] + perl $0 + + [<M> ...] A non-empty integer matrix +END + +#------------------------------------------------------------------------------- +BEGIN +#------------------------------------------------------------------------------- +{ + $| = 1; + print "\nChallenge 257, Task #2: Reduced Row Echelon (Perl)\n\n"; +} + +#=============================================================================== +MAIN: +#=============================================================================== +{ + if (scalar @ARGV == 0) + { + run_tests(); + } + else + { + my $matrix = parse_matrix( \@ARGV ); + + print_matrix( 'Input: $M = ', $matrix ); + + printf "Output: %d\n", is_reduced_row_echelon( $matrix ); + } +} + +#------------------------------------------------------------------------------- +sub is_reduced_row_echelon +#------------------------------------------------------------------------------- +{ + my ($matrix) = @_; + + # Test matrix properties 1 and 2: + # 1. If a row does not consist entirely of zeros, then the first nonzero + # number in the row is a 1. We call this the leading 1. + # 2. If there are any rows that consist entirely of zeros, then they are + # grouped together at the bottom of the matrix. + + my $row_types = classify_rows( $matrix ); + my $all_zeros = 0; + + for my $type (@$row_types) + { + if ($type == AllZeros) + { + $all_zeros = 1; + } + elsif ($type == LeadingOne) + { + return 0 if $all_zeros; # Requirement 2 + } + else + { + return 0; # Requirement 1 + } + } + + # Test matrix properties 3 and 4: + # 3. In any two successive rows that do not consist entirely of zeros, the + # leading 1 in the lower row occurs farther to the right than the leading + # 1 in the higher row. + # 4. Each column that contains a leading 1 has zeros everywhere else in that + # column. + + return check_leading_ones( $matrix, $row_types ); +} + +#------------------------------------------------------------------------------- +sub classify_rows +#------------------------------------------------------------------------------- +{ + my ($matrix) = @_; + my $width = scalar @{ $matrix->[ 0 ] }; + my @row_types; + + L_OUTER: + for my $r (0 .. $#$matrix) + { + my $row = $matrix->[ $r ]; + + for my $c (0 .. $width - 1) + { + my $element = $row->[ $c ]; + + if ($element == 1) + { + push @row_types, LeadingOne; + next L_OUTER; + } + elsif ($element != 0) + { + push @row_types, Other; + next L_OUTER; + } + } + + push @row_types, AllZeros; + } + + return \@row_types; +} + +#------------------------------------------------------------------------------- +sub check_leading_ones +#------------------------------------------------------------------------------- +{ + my ($matrix, $row_t) = @_; + my $width = scalar @{ $matrix->[ 0 ] }; + my $last_one = -1; + + for my $r (0 .. $#$matrix) + { + last if $row_t->[ $r ] == AllZeros; + + my $row = $matrix->[ $r ]; + + for my $c (0 .. $width - 1) + { + my $element = $row->[ $c ]; + + if ($element == 1) + { + return 0 unless $c > $last_one; # Test Requirement 3 + + $last_one = $c; + + for my $rr (0 .. $#$matrix) # Test Requirement 4 + { + return 0 unless $rr == $r || $matrix->[ $rr ][ $c ] == 0; + } + + last; + } + } + } + + return 1; +} + +#------------------------------------------------------------------------------- +sub parse_matrix +#------------------------------------------------------------------------------- +{ + my ($M) = @_; + my (@matrix, $num_cols); + + for my $row_str (@$M) + { + my @row; + + for my $elem (grep { / \S /x } split / \s+ /x, $row_str) + { + if ($elem =~ / ^ $RE{num}{int} $ /x) + { + push @row, $elem; + } + else + { + error( qq[Element "$elem" is not a valid integer] ); + } + } + + push @matrix, \@row; + + if (defined $num_cols) + { + scalar @row == $num_cols + or error( 'The input matrix is not rectangular' ); + } + else + { + $num_cols = scalar @row; + $num_cols > 0 or error( 'Empty row' ); + } + } + + return \@matrix; +} + +#------------------------------------------------------------------------------- +sub print_matrix +#------------------------------------------------------------------------------- +{ + my ($prefix, $matrix) = @_; + my $tab = ' ' x length $prefix; + my @width = (1) x scalar @{ $matrix->[ 0 ] }; + + for my $row (@$matrix) + { + for my $i (0 .. $#$row) + { + my $w = length $row->[ $i ]; + + $width[ $i ] = $w if $w > $width[ $i ]; + } + } + + print "$prefix\[\n"; + + for my $row (@$matrix) + { + my @row_str; + + for my $i (0 .. $#$row) + { + push @row_str, sprintf '%*d', $width[ $i ], $row->[ $i ]; + } + + printf "%s [%s]\n", $tab, join ', ', @row_str; + } + + print "$tab]\n"; +} + +#------------------------------------------------------------------------------- +sub run_tests +#------------------------------------------------------------------------------- +{ + print "Running the test suite\n"; + + while (my $line = <DATA>) + { + chomp $line; + + my ($test_name, $matrix_str, $expected) = split / \| /x, $line; + + for ($test_name, $matrix_str, $expected) + { + s/ ^ \s+ //x; + s/ \s+ $ //x; + } + + my @M = split / \; /x, $matrix_str; + my $matrix = parse_matrix( \@M ); + my $is_rre = is_reduced_row_echelon( $matrix ); + + is $is_rre, $expected, $test_name; + } + + done_testing; +} + +#------------------------------------------------------------------------------- +sub error +#------------------------------------------------------------------------------- +{ + my ($message) = @_; + + die "ERROR: $message\n$USAGE"; +} + +################################################################################ + +__DATA__ +Example 0|1 0 0 1 ; 0 1 0 2 ; 0 0 1 3 |1 +Example 1|1 1 0 ; 0 1 0 ; 0 0 0 |0 +Example 2|0 1 -2 0 1; 0 0 0 1 3; 0 0 0 0 0; 0 0 0 0 0|1 +Example 3|1 0 0 4 ; 0 1 0 7 ; 0 0 1 -1 |1 +Example 4|0 1 -2 0 1; 0 0 0 0 0; 0 0 0 1 3; 0 0 0 0 0|0 +Example 5|0 1 0 ; 1 0 0 ; 0 0 0 |0 +Example 6|4 0 0 0 ; 0 1 0 7 ; 0 0 1 -1 |0 diff --git a/challenge-257/athanasius/raku/ch-1.raku b/challenge-257/athanasius/raku/ch-1.raku new file mode 100644 index 0000000000..21c615c9d8 --- /dev/null +++ b/challenge-257/athanasius/raku/ch-1.raku @@ -0,0 +1,178 @@ +use v6d; + +################################################################################ +=begin comment + +Perl Weekly Challenge 257 +========================= + +TASK #1 +------- +*Smaller than Current* + +Submitted by: Mohammad Sajid Anwar + +You are given an array of integers, @ints. + +Write a script to find out how many integers are smaller than current i.e. +foreach ints[i], count ints[j] < ints[i] where i != j. + +Example 1 + + Input: @ints = (5, 2, 1, 6) + Output: (2, 1, 0, 3) + + For $ints[0] = 5, there are two integers (2,1) smaller than 5. + For $ints[1] = 2, there is one integer (1) smaller than 2. + For $ints[2] = 1, there is none integer smaller than 1. + For $ints[3] = 6, there are three integers (5,2,1) smaller than 6. + +Example 2 + + Input: @ints = (1, 2, 0, 3) + Output: (1, 2, 0, 3) + +Example 3 + + Input: @ints = (0, 1) + Output: (0, 1) + +Example 4 + + Input: @ints = (9, 4, 9, 2) + Output: (2, 1, 2, 0) + +=end comment +################################################################################ + +#--------------------------------------# +# Copyright © 2024 PerlMonk Athanasius # +#--------------------------------------# + +#=============================================================================== +=begin comment + +Interface +--------- +If no command-line arguments are given, the test suite is run. + +=end comment +#=============================================================================== + +use Test; + +#------------------------------------------------------------------------------- +BEGIN +#------------------------------------------------------------------------------- +{ + "\nChallenge 257, Task #1: Smaller than Current (Raku)\n".put; +} + +#=============================================================================== +multi sub MAIN +( + #| A non-empty array of integers + + *@ints where { .elems > 0 && .all ~~ Int:D } +) +#=============================================================================== +{ + "Input: \@ints = (%s)\n".printf: @ints.join: ', '; + + my UInt @counts = count-smaller-than-current( @ints ); + + "Output: (%s)\n".printf: @counts.join: ', '; +} + +#=============================================================================== +multi sub MAIN() # No input: run the test suite +#=============================================================================== +{ + run-tests(); +} + +#------------------------------------------------------------------------------- +sub count-smaller-than-current( List:D[Int:D] $ints --> List:D[UInts:D] ) +#------------------------------------------------------------------------------- +{ + my UInt @counts; + + for 0 .. $ints.end -> UInt $i + { + my UInt $count = 0; + + for 0 .. $ints.end -> UInt $j + { + next if $i == $j; + + ++$count if $ints[ $j ] < $ints[ $i ]; + } + + @counts.push: $count; + } + + return @counts; +} + +#------------------------------------------------------------------------------- +sub run-tests() +#------------------------------------------------------------------------------- +{ + 'Running the test suite'.put; + + for test-data.lines -> Str $line + { + my Str ($test-name, $int-str, $exp-str) = $line.split: / \| /; + + for $test-name, $int-str, $exp-str + { + s/ ^ \s+ //; + s/ \s+ $ //; + } + + my Int @ints = ($int-str.split: / \s+ /, :skip-empty).map: { .Int }; + my UInt @exp = ($exp-str.split: / \s+ /, :skip-empty).map: { .Int }; + my UInt @counts = count-smaller-than-current( @ints ); + + is-deeply @counts, @exp, $test-name; + } + + done-testing; +} + +#------------------------------------------------------------------------------- +sub error( Str:D $message ) +#------------------------------------------------------------------------------- +{ + "ERROR: $message".put; + + USAGE(); + + exit 0; +} + +#------------------------------------------------------------------------------- +sub USAGE() +#------------------------------------------------------------------------------- +{ + my Str $usage = $*USAGE; + + $usage ~~ s:g/ ($*PROGRAM-NAME) /raku $0/; + + $usage.put; +} + +#------------------------------------------------------------------------------- +sub test-data( --> Str:D ) +#------------------------------------------------------------------------------- +{ + return q:to/END/; + Example 1| 5 2 1 6|2 1 0 3 + Example 2| 1 2 0 3|1 2 0 3 + Example 3| 0 1 |0 1 + Example 4| 9 4 9 2|2 1 2 0 + Negatives|-2 -2 -1 |0 0 2 + END +} + +################################################################################ diff --git a/challenge-257/athanasius/raku/ch-2.raku b/challenge-257/athanasius/raku/ch-2.raku new file mode 100644 index 0000000000..4bb6a71228 --- /dev/null +++ b/challenge-257/athanasius/raku/ch-2.raku @@ -0,0 +1,410 @@ +use v6d; + +################################################################################ +=begin comment + +Perl Weekly Challenge 257 +========================= + +TASK #2 +------- +*Reduced Row Echelon* + +Submitted by: Ali Moradi + +Given a matrix M, check whether the matrix is in reduced row echelon form. + +A matrix must have the following properties to be in reduced row echelon form: + + 1. If a row does not consist entirely of zeros, then the first + nonzero number in the row is a 1. We call this the leading 1. + 2. If there are any rows that consist entirely of zeros, then + they are grouped together at the bottom of the matrix. + 3. In any two successive rows that do not consist entirely of zeros, + the leading 1 in the lower row occurs farther to the right than + the leading 1 in the higher row. + 4. Each column that contains a leading 1 has zeros everywhere else + in that column. + +For example: + + [ + [1,0,0,1], + [0,1,0,2], + [0,0,1,3] + ] + +The above matrix is in reduced row echelon form since the first nonzero number +in each row is a 1, leading 1s in each successive row are farther to the right, +and above and below each leading 1 there are only zeros. + +For more information check out this wikipedia +[https://en.wikipedia.org/wiki/Row_echelon_form|article]. + +Example 1 + + Input: $M = [ + [1, 1, 0], + [0, 1, 0], + [0, 0, 0] + ] + Output: 0 + +Example 2 + + Input: $M = [ + [0, 1,-2, 0, 1], + [0, 0, 0, 1, 3], + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0] + ] + Output: 1 + +Example 3 + + Input: $M = [ + [1, 0, 0, 4], + [0, 1, 0, 7], + [0, 0, 1,-1] + ] + Output: 1 + +Example 4 + + Input: $M = [ + [0, 1,-2, 0, 1], + [0, 0, 0, 0, 0], + [0, 0, 0, 1, 3], + [0, 0, 0, 0, 0] + ] + Output: 0 + +Example 5 + + Input: $M = [ + [0, 1, 0], + [1, 0, 0], + [0, 0, 0] + ] + Output: 0 + +Example 6 + + Input: $M = [ + [4, 0, 0, 0], + [0, 1, 0, 7], + [0, 0, 1,-1] + ] + Output: 0 + +=end comment +################################################################################ + +#--------------------------------------# +# Copyright © 2024 PerlMonk Athanasius # +#--------------------------------------# + +#=============================================================================== +=begin comment + +Interface +--------- +1. If no command-line arguments are given, the test suite is run. Otherwise: +2. The input matrix M is entered on the command-line as a non-empty list of + strings (the matrix rows) containing elements separated by whitespace. For + example, the matrix: + + [ 1 1 0 ] + [ 0 1 0 ] + [ 0 0 0 ] + + is entered as: >raku ch-2.raku "1 1 0" "0 1 0" "0 0 1" + +Assumptions +----------- +1. The input matrix M is an integer matrix. +2. M is not an empty matrix. + +Note +---- +Matrix-handling code is adapted from the solution to Task 2 for Week 248. + +=end comment +#=============================================================================== + +use Test; + +enum RowType < AllZeros LeadingOne Other >; +subset Matrix of Array where * ~~ Array[Array[Int]]; + +#------------------------------------------------------------------------------- +BEGIN +#------------------------------------------------------------------------------- +{ + "\nChallenge 257, Task #2: Reduced Row Echelon (Raku)\n".put; +} + +#=============================================================================== +multi sub MAIN +( + *@M where { .all ~~ Str:D && .elems > 0 } #= A non-empty integer matrix +) +#=============================================================================== +{ + my Matrix $matrix = parse-matrix( @M ); + + print-matrix( 'Input: $M = ', $matrix ); + + my Bool $is-rre = is-reduced-row-echelon( $matrix ); + + "Output: %d\n".printf: $is-rre ?? 1 !! 0; +} + +#=============================================================================== +multi sub MAIN() # No input: run the test suite +#=============================================================================== +{ + run-tests(); +} + +#------------------------------------------------------------------------------- +sub is-reduced-row-echelon( Matrix:D $matrix --> Bool:D ) +#------------------------------------------------------------------------------- +{ + # Test matrix properties 1 and 2: + # 1. If a row does not consist entirely of zeros, then the first nonzero + # number in the row is a 1. We call this the leading 1. + # 2. If there are any rows that consist entirely of zeros, then they are + # grouped together at the bottom of the matrix. + + my RowType @row-types = classify-rows( $matrix ); + my Bool $all-zeros = False; + + for @row-types -> RowType $type + { + given $type + { + when AllZeros { $all-zeros = True; } + when LeadingOne { return False if $all-zeros; } # Requirement 2 + when Other { return False; } # Requirement 1 + } + } + + # Test matrix properties 3 and 4: + # 3. In any two successive rows that do not consist entirely of zeros, the + # leading 1 in the lower row occurs farther to the right than the leading + # 1 in the higher row. + # 4. Each column that contains a leading 1 has zeros everywhere else in that + # column. + + return check-leading-ones( $matrix, @row-types ); +} + +#------------------------------------------------------------------------------- +sub classify-rows( Matrix:D $matrix --> List:D[RowType:D] ) +#------------------------------------------------------------------------------- +{ + my RowType @row-types; + my UInt $width = $matrix[ 0 ].elems; + + L-OUTER: + for 0 .. $matrix.end -> UInt $r + { + my Array[Int] $row = $matrix[ $r ]; + + for 0 .. $width - 1 -> UInt $c + { + my Int $element = $row[ $c ]; + + if $element == 1 + { + @row-types.push: LeadingOne; + next L-OUTER; + } + elsif $element != 0 + { + @row-types.push: Other; + next L-OUTER; + } + } + + @row-types.push: AllZeros; + } + + return @row-types; +} + +#------------------------------------------------------------------------------- +sub check-leading-ones( Matrix:D $matrix, List:D[RowType:D] $row-t --> Bool:D ) +#------------------------------------------------------------------------------- +{ + my UInt $width = $matrix[ 0 ].elems; + my Int $last-one = -1; + + for 0 .. $matrix.end -> UInt $r + { + last if $row-t[ $r ] == AllZeros; + + my Array[Int] $row = $matrix[ $r ]; + + for 0 .. $width - 1 -> UInt $c + { + my Int $element = $row[ $c ]; + + if $element == 1 + { + return False unless $c > $last-one; # Test Requirement 3 + + $last-one = $c; + + for 0 .. $matrix.end -> UInt $rr # Test Requirement 4 + { + return False unless $rr == $r || $matrix[ $rr; $c ] == 0; + } + + last; + } + } + } + + return True; +} + +#------------------------------------------------------------------------------- +sub parse-matrix( List:D[Str:D] $M --> Matrix:D ) +#------------------------------------------------------------------------------- +{ + my Matrix $matrix = Array[Array[Int]].new; + my UInt $num-cols; + + for @$M -> Str $row-str + { + my Int @row; + + for $row-str.split( / \s+ /, :skip-empty ) -> Str $elem + { + if +$elem ~~ Int:D + { + @row.push: +$elem; + } + else + { + error( qq[Element "$elem" is not a valid integer] ); + } + } + + $matrix.push: @row; + + if $num-cols.defined + { + @row.elems == $num-cols + or error( 'The input matrix is not rectangular' ); + } + else + { + ($num-cols = @row.elems) > 0 or error( 'Empty row' ); + } + } + + return $matrix; +} + +#------------------------------------------------------------------------------- +sub print-matrix( Str:D $prefix, Matrix:D $matrix ) +#------------------------------------------------------------------------------- +{ + my Str $tab = ' ' x $prefix.chars; + my UInt @width = 1 xx $matrix[ 0 ].elems; + + for @$matrix -> Int @row + { + for 0 .. @row.end -> UInt $i + { + my UInt $w = @row[ $i ].chars; + + @width[ $i ] = $w if $w > @width[ $i ]; + } + } + + "$prefix\[".put; + + for @$matrix -> Int @row + { + my Str @row-str; + + for 0 .. @row.end -> UInt $i + { + @row-str.push: '%*d'.sprintf: @width[ $i ], @row[ $i ]; + } + + "%s [%s]\n".printf: $tab, @row-str.join: ', '; + } + + "$tab]".put; +} + +#------------------------------------------------------------------------------- +sub run-tests() +#------------------------------------------------------------------------------- +{ + 'Running the test suite'.put; + + for test-data.lines -> Str $line + { + my Str ($test-name, $matrix-str, $exp-str) = $line.split: / \| /; + + for $test-name, $matrix-str, $exp-str + { + s/ ^ \s+ //; + s/ \s+ $ //; + } + + my Str @M = $matrix-str.split: / \; /, :skip-empty; + my Matrix $matrix = parse-matrix( @M ); < |
