aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohammad S Anwar <Mohammad.Anwar@yahoo.com>2023-04-10 00:30:21 +0100
committerGitHub <noreply@github.com>2023-04-10 00:30:21 +0100
commit2699911c7bf1f409e74fd45888441d990e5f81da (patch)
tree5e8b19f6207a3380cefa5836da45edda0f13c8a1
parentc192f7be97c345716596778d54d9729573449b4b (diff)
parentab7286c437838e6e823b8c1462b09d7fd8ba40e8 (diff)
downloadperlweeklychallenge-club-2699911c7bf1f409e74fd45888441d990e5f81da.tar.gz
perlweeklychallenge-club-2699911c7bf1f409e74fd45888441d990e5f81da.tar.bz2
perlweeklychallenge-club-2699911c7bf1f409e74fd45888441d990e5f81da.zip
Merge pull request #7872 from PerlMonk-Athanasius/branch-for-challenge-211
Perl & Raku solutions to Tasks 1 & 2 for Week 211
-rw-r--r--challenge-211/athanasius/perl/ch-1.pl197
-rw-r--r--challenge-211/athanasius/perl/ch-2.pl254
-rw-r--r--challenge-211/athanasius/raku/ch-1.raku217
-rw-r--r--challenge-211/athanasius/raku/ch-2.raku199
4 files changed, 867 insertions, 0 deletions
diff --git a/challenge-211/athanasius/perl/ch-1.pl b/challenge-211/athanasius/perl/ch-1.pl
new file mode 100644
index 0000000000..c0e5c08858
--- /dev/null
+++ b/challenge-211/athanasius/perl/ch-1.pl
@@ -0,0 +1,197 @@
+#!perl
+
+################################################################################
+=comment
+
+Perl Weekly Challenge 211
+=========================
+
+TASK #1
+-------
+*Toeplitz Matrix*
+
+Submitted by: Mohammad S Anwar
+
+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
+
+=cut
+################################################################################
+
+#--------------------------------------#
+# Copyright © 2023 PerlMonk Athanasius #
+#--------------------------------------#
+
+#===============================================================================
+=comment
+
+Interface
+---------
+If no command-line arguments are given, the test suite is run.
+
+=cut
+#===============================================================================
+
+use strict;
+use warnings;
+use Const::Fast;
+use Data::Dump qw( pp );
+use Test::More;
+
+const my $USAGE =>
+"Usage:
+ perl $0 <matrix>
+ perl $0
+
+ <matrix> String representing a matrix\n";
+
+#-------------------------------------------------------------------------------
+BEGIN
+#-------------------------------------------------------------------------------
+{
+ $| = 1;
+ print "\nChallenge 211, Task #1: Toeplitz Matrix (Perl)\n\n";
+}
+
+#===============================================================================
+MAIN:
+#===============================================================================
+{
+ my $args = scalar @ARGV;
+
+ if ($args == 0)
+ {
+ run_tests();
+ }
+ elsif ($args == 1)
+ {
+ my $matrix = parse_matrix_string( $ARGV[ 0 ] );
+
+ printf "Input: \@matrix = %s\n", pp( $matrix );
+
+ printf "Output: %s\n", is_toeplitz_matrix( $matrix ) ? 'True' : 'False';
+ }
+ else
+ {
+ error( "Expected 1 or 0 command line arguments, found $args");
+ }
+}
+
+#-------------------------------------------------------------------------------
+sub is_toeplitz_matrix
+#-------------------------------------------------------------------------------
+{
+ my ($matrix) = @_;
+ my $rows = scalar @$matrix;
+ my $cols = scalar $matrix->[ 0 ]->@*;
+
+ for my $row (0 .. $rows - 2)
+ {
+ for my $col (0 .. $cols - 2)
+ {
+ return 0 unless $matrix->[ $row ][ $col ] eq
+ $matrix->[ $row + 1 ][ $col + 1 ];
+ }
+ }
+
+ return 1;
+}
+
+#-------------------------------------------------------------------------------
+sub parse_matrix_string
+#-------------------------------------------------------------------------------
+{
+ my ($string) = @_;
+
+ $string =~ / ^ \s* \[ \s* (.+) \] \s* $ /x
+ or error( 'Malformed matrix string' );
+
+ $string = $1;
+
+ $string =~ / ^ \[ .+ \] $ /x
+ or error( 'Malformed matrix string' );
+
+ my @matrix;
+
+ while ($string =~ / \G \,? \s* \[ \s* (.+?) \] /gx)
+ {
+ push @matrix, [ split / , \s* /x, $1 ];
+ }
+
+ scalar @matrix > 0
+ or error( 'Empty matrix' );
+
+ my $cols = scalar $matrix[ 0 ]->@*;
+
+ for my $row (1 .. $#matrix)
+ {
+ scalar( $matrix[ $row ]->@* ) == $cols
+ or error( 'Ragged array' );
+ }
+
+ return \@matrix;
+}
+
+#-------------------------------------------------------------------------------
+sub run_tests
+#-------------------------------------------------------------------------------
+{
+ print "Running the test suite\n";
+
+ while (my $line = <DATA>)
+ {
+ chomp $line;
+
+ my ($test_name, $input, $expected) = split / \| /x, $line;
+
+ $test_name =~ s/ \s+ $ //x; # Trim whitespace
+ $input =~ s/ \s+ $ //x;
+
+ my $matrix = parse_matrix_string( $input );
+ my $got = is_toeplitz_matrix( $matrix ) ? 'True' : 'False';
+
+ is $got, $expected, $test_name;
+ }
+
+ done_testing;
+}
+
+#-------------------------------------------------------------------------------
+sub error
+#-------------------------------------------------------------------------------
+{
+ my ($message) = @_;
+
+ die "ERROR: $message\n$USAGE";
+}
+
+################################################################################
+
+__DATA__
+Example 1 |[[4,3,2,1],[5,4,3,2],[6,5,4,3]] |True
+Example 2 |[[1,2,3],[3,2,1]] |False
+Single element|[[42]] |True
+Single row |[[17,-3,12,9,5,0,7]] |True
+Single column |[[apple][banana][guava][pear]] |True
+Alternating |[[0,1,0,1,0],[1,0,1,0,1],[0,1,0,1,0]]|True
+Deceptive 1 |[[0,1,0,1,0],[1,0,1,0,1],[0,1,O,1,0]]|False
+Deceptive 2 |[[O,1,0,1,0],[1,O,1,0,1],[0,1,O,1,0]]|True
diff --git a/challenge-211/athanasius/perl/ch-2.pl b/challenge-211/athanasius/perl/ch-2.pl
new file mode 100644
index 0000000000..d871974f1c
--- /dev/null
+++ b/challenge-211/athanasius/perl/ch-2.pl
@@ -0,0 +1,254 @@
+#!perl
+
+################################################################################
+=comment
+
+Perl Weekly Challenge 211
+=========================
+
+TASK #2
+-------
+*Split Same Average*
+
+Submitted by: Mohammad S Anwar
+
+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
+
+=cut
+################################################################################
+
+#--------------------------------------#
+# Copyright © 2023 PerlMonk Athanasius #
+#--------------------------------------#
+
+#===============================================================================
+=comment
+
+Interface
+---------
+1. If no command-line arguments are given, the test suite is run. Otherwise:
+2. If $VERBOSE is set to a true value, an output of "True" is followed by an
+ explanation of how the array may be split (using the first solution found).
+
+Notes
+-----
+1. Duplicates are allowed in the input array.
+2. Where more than one solution is possible, the preferred solution is the one
+ in which the partitions are closest in size.
+3. The algorithm used is a simple search of all possible partitions formed from
+ members of the input array; obviously, for larger arrays, this will not scale
+ well.
+
+=cut
+#===============================================================================
+
+use strict;
+use warnings;
+use experimental qw( smartmatch );
+use Const::Fast;
+use Math::Prime::Util qw( forcomb lastfor );
+use Regexp::Common qw( number );
+use Test::More;
+
+const my $EPSILON => 10 ** -9;
+const my $VERBOSE => 1;
+const my $USAGE =>
+"Usage:
+ perl $0 [<nums> ...]
+ perl $0
+
+ [<nums> ...] A list of integers\n";
+
+#-------------------------------------------------------------------------------
+BEGIN
+#-------------------------------------------------------------------------------
+{
+ $| = 1;
+ print "\nChallenge 211, Task #2: Split Same Average (Perl)\n\n";
+}
+
+#===============================================================================
+MAIN:
+#===============================================================================
+{
+ if (scalar @ARGV == 0)
+ {
+ run_tests();
+ }
+ else
+ {
+ / ^ $RE{num}{int} $ /x
+ or die qq[ERROR: "$_" is not a valid integer\n$USAGE]
+ for @ARGV;
+
+ printf "Input: \@list = (%s)\n", join ', ', @ARGV;
+
+ my $solution = split_same_avg( \@ARGV );
+
+ printf "Output: %s\n", $solution->[ 0 ] ? 'True' : 'False';
+
+ if ($VERBOSE && $solution->[ 0 ])
+ {
+ printf "\nWe can split the given array into (%s) and (%s)\n",
+ join( ', ', $solution->[ 1 ]->@* ),
+ join( ', ', $solution->[ 2 ]->@* );
+
+ print 'The average of each of these arrays is ' . $solution->[ 3 ] .
+ "\n";
+ }
+ }
+}
+
+#-------------------------------------------------------------------------------
+sub split_same_avg
+#-------------------------------------------------------------------------------
+{
+ my ($nums) = @_;
+
+ if (scalar @$nums >= 2)
+ {
+ my $found = 0;
+
+ # Prefer the solution in which the partitions are closest in size
+
+ for my $k (reverse 1 .. int( scalar( @$nums ) / 2 ))
+ {
+ my (@part1, @part2, $avg1, $avg2);
+
+ forcomb
+ {
+ @part1 = (@$nums)[ @_ ];
+ @part2 = complement( $nums, \@part1 );
+ $avg1 = average( \@part1 );
+ $avg2 = average( \@part2 );
+
+ $found = 1, lastfor if abs($avg1 - $avg2) < $EPSILON;
+
+ } @$nums, $k;
+
+ if ($found)
+ {
+ @part1 = sort { $a <=> $b } @part1;
+ @part2 = sort { $a <=> $b } @part2;
+
+ return [ 1, \@part1, \@part2, $avg1 ];
+ }
+ }
+ }
+
+ return [ 0, undef, undef, undef ];
+}
+
+#-------------------------------------------------------------------------------
+sub complement
+#-------------------------------------------------------------------------------
+{
+ my ($uni_ref, $bag_ref) = @_;
+
+ my @uni = sort { $a <=> $b } @$uni_ref;
+ my @bag = sort { $a <=> $b } @$bag_ref;
+ my @comp;
+
+ while (@uni && @bag)
+ {
+ my $elem = shift @uni;
+
+ if ($elem == $bag[ 0 ])
+ {
+ shift @bag;
+ }
+ else
+ {
+ push @comp, $elem;
+ }
+ }
+
+ push @comp, @uni;
+
+ return @comp;
+}
+
+#-------------------------------------------------------------------------------
+sub average
+#-------------------------------------------------------------------------------
+{
+ my ($list) = @_;
+ my $elems = scalar @$list;
+
+ return if $elems == 0;
+
+ my $sum = 0;
+ $sum += $_ for @$list;
+
+ return $sum / $elems;
+}
+
+#-------------------------------------------------------------------------------
+sub run_tests
+#-------------------------------------------------------------------------------
+{
+ print "Running the test suite\n";
+
+ while (my $line = <DATA>)
+ {
+ chomp $line;
+
+ my ($test_name, $input, @output) = split / \| /x, $line;
+
+ for ($test_name, $input, @output) # Trim whitespace
+ {
+ s/ ^ \s+ //x;
+ s/ \s+ $ //x;
+ }
+
+ my @nums = split / \, \s* /x, $input;
+ my $expected = $output[ 0 ];
+ my $got = split_same_avg( \@nums );
+
+ is $got->[ 0 ], $expected, $test_name;
+
+ if ($got->[ 0 ] && $expected)
+ {
+ my @part1 = split / \, \s* /x, $output[ 1 ];
+ my @part2 = split / \, \s* /x, $output[ 2 ];
+ my $avg = $output[ 3 ];
+
+ ok $got->[ 1 ] ~~ @part1, "$test_name: partition 1";
+ ok $got->[ 2 ] ~~ @part2, "$test_name: partition 2";
+ is $got->[ 3 ], $avg, "$test_name: average";
+ }
+ }
+
+ done_testing;
+}
+
+################################################################################
+
+# Note: The specific solution to Example 1 has been changed in accordance with
+# the algorithm used in split_same_avg()
+
+__DATA__
+Example 1| 1, 2, 3, 4, 5, 6, 7, 8|1| 1, 2, 7, 8| 3, 4, 5, 6| 4.5
+Example 2| 1, 3 |0
+Negatives|-4,-2,-3 |1|-3 |-4,-2 |-3
+Mixed 1 |-7, 5, 0, 9,12,-1, 4, 6|1|-7, 4, 5,12|-1, 0, 6, 9| 3.5
+Mixed 2 |-7, 5, 0, 9,12,-1, 4, 5|0
+Same | 4, 4 |1| 4 | 4 | 4
+Zeros | 0, 0, 0 |1| 0 | 0, 0 | 0
+One |42 |0
diff --git a/challenge-211/athanasius/raku/ch-1.raku b/challenge-211/athanasius/raku/ch-1.raku
new file mode 100644
index 0000000000..2f0e8ec185
--- /dev/null
+++ b/challenge-211/athanasius/raku/ch-1.raku
@@ -0,0 +1,217 @@
+use v6d;
+
+################################################################################
+=begin comment
+
+Perl Weekly Challenge 211
+=========================
+
+TASK #1
+-------
+*Toeplitz Matrix*
+
+Submitted by: Mohammad S Anwar
+
+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
+
+=end comment
+################################################################################
+
+#--------------------------------------#
+# Copyright © 2023 PerlMonk Athanasius #
+#--------------------------------------#
+
+#===============================================================================
+=begin comment
+
+Interface
+---------
+If no command-line arguments are given, the test suite is run.
+
+=end comment
+#===============================================================================
+
+use Test;
+
+#-------------------------------------------------------------------------------
+BEGIN
+#-------------------------------------------------------------------------------
+{
+ "\nChallenge 211, Task #1: Toeplitz Matrix (Raku)\n".put;
+}
+
+#===============================================================================
+multi sub MAIN
+(
+ Str:D $matrix #= String representing a matrix
+)
+#===============================================================================
+{
+ my @matrix = parse-matrix-string( $matrix );
+
+ "Input: \@matrix = %s\n".printf: format-matrix( @matrix );
+
+ "Output: %s\n".printf: is-toeplitz-matrix( @matrix ) ?? 'True' !! 'False';
+}
+
+#===============================================================================
+multi sub MAIN() # No input: run the test suite
+#===============================================================================
+{
+ run-tests();
+}
+
+#-------------------------------------------------------------------------------
+sub is-toeplitz-matrix( List:D[List:D[Str:D]] $matrix --> Bool:D )
+#-------------------------------------------------------------------------------
+{
+ my UInt $rows = $matrix.elems;
+ my UInt $cols = $matrix[ 0 ].elems;
+
+ for 0 .. $rows - 2 -> UInt $row
+ {
+ for 0 .. $cols - 2 -> UInt $col
+ {
+ return False unless $matrix[ $row; $col ] eq
+ $matrix[ $row + 1; $col + 1 ];
+ }
+ }
+
+ return True;
+}
+
+#-------------------------------------------------------------------------------
+sub parse-matrix-string( Str:D $matrix --> List:D[List:D[Str:D]] )
+#-------------------------------------------------------------------------------
+{
+ $matrix ~~ / ^ \s* \[ \s* (.+) \] \s* $ /
+ or error( 'Malformed matrix string (1)' );
+
+ my Str $string = $0.Str;
+
+ $string ~~ / ^ \[ .+ \] \s* $ /
+ or error( 'Malformed matrix string (2)' );
+
+ my Array[Str] @matrix;
+ my Match @matches = $string ~~ m:g/ \,? \s* \[ \s* .+? \] /;
+
+ for @matches -> Match $match
+ {
+ $match.Str ~~ / ^ \,? \s* \[ (.+) \] $ /
+ or error( 'Malformed matrix string (3)' );
+
+ my Str @elems = $0.split: / \, \s* /;
+
+ s/ ^ \s+ //, s/ \s+ $ // for @elems;
+
+ @matrix.push: Array[Str].new: @elems;
+ }
+
+ @matrix.elems > 0 or error( 'Empty matrix' );
+
+ my UInt $cols = @matrix[ 0 ].elems;
+
+ for 1 .. @matrix.end -> UInt $row
+ {
+ @matrix[ $row ].elems == $cols or error( 'Ragged array' );
+ }
+
+ return @matrix;
+}
+
+#-------------------------------------------------------------------------------
+sub format-matrix( List:D[List:D[Str:D]] $matrix --> Str:D )
+#-------------------------------------------------------------------------------
+{
+ my Str @rows;
+
+ for @$matrix -> List $row
+ {
+ @rows.push: '[' ~ $row.join( ', ' ) ~ ']';
+ }
+
+ return '[ ' ~ @rows.join( ', ' ) ~ ' ]';
+}
+
+#-------------------------------------------------------------------------------
+sub run-tests()
+#-------------------------------------------------------------------------------
+{
+ 'Running the test suite'.put;
+
+ for test-data.lines -> Str $line
+ {
+ my Str ($test-name, $input, $expected) = $line.split: / \| /;
+
+ $test-name ~~ s/ \s+ $ //; # Trim whitespace
+ $input ~~ s/ \s+ $ //;
+
+ my Array[Array[Str]] $matrix = parse-matrix-string( $input );
+
+ my Str $got = is-toeplitz-matrix( $matrix ) ?? 'True' !! 'False';
+
+ is $got, $expected, $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 |[[4,3,2,1],[5,4,3,2],[6,5,4,3]] |True
+ Example 2 |[[1,2,3],[3,2,1]] |False
+ Single element|[[42]] |True
+ Single row |[[17,-3,12,9,5,0,7]] |True
+ Single column |[[apple][banana][guava][pear]] |True
+ Alternating |[[0,1,0,1,0],[1,0,1,0,1],[0,1,0,1,0]]|True
+ Deceptive 1 |[[0,1,0,1,0],[1,0,1,0,1],[0,1,O,1,0]]|False
+ Deceptive 2 |[[O,1,0,1,0],[1,O,1,0,1],[0,1,O,1,0]]|True
+ END
+}
+
+################################################################################
diff --git a/challenge-211/athanasius/raku/ch-2.raku b/challenge-211/athanasius/raku/ch-2.raku
new file mode 100644
index 0000000000..84cea96e02
--- /dev/null
+++ b/challenge-211/athanasius/raku/ch-2.raku
@@ -0,0 +1,199 @@
+use v6d;
+
+################################################################################
+=begin comment
+
+Perl Weekly Challenge 211
+=========================
+
+TASK #2
+-------
+*Split Same Average*
+
+Submitted by: Mohammad S Anwar
+
+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
+
+=end comment
+################################################################################
+
+#--------------------------------------#
+# Copyright © 2023 PerlMonk Athanasius #
+#--------------------------------------#
+
+#===============================================================================
+=begin comment
+
+Interface
+---------
+1. If no command-line arguments are given, the test suite is run. Otherwise:
+2. If the first argument is negative, it must be preceded by "--".
+3. If $VERBOSE is True, an output of "True" is followed by an explanation of how
+ the array may be split (using the first solution found).
+
+Notes
+-----
+1. Duplicates are allowed in the input array. Raku's built-in class Bag (for
+ multisets) is a useful container.
+2. Where more than one solution is possible, the preferred solution is one in
+ which the partitions are closest in size.
+3. The algorithm used is a simple search of all possible partitions formed from
+ members of the input array; obviously, for larger arrays, this will not scale
+ well.
+
+=end comment
+#===============================================================================
+
+use Test;
+
+my Bool constant $VERBOSE = True;
+
+subset Solution of List where (Bool:D, Bag, Bag, Rat);
+
+#-------------------------------------------------------------------------------
+BEGIN
+#-------------------------------------------------------------------------------
+{
+ "\nChallenge 211, Task #2: Split Same Average (Raku)\n".put;
+}
+
+#===============================================================================
+multi sub MAIN
+(
+ *@nums where { .elems > 0 && .all ~~ Int:D } #= A list of integers
+)
+#===============================================================================
+{
+ "Input: \@nums = (%s)\n".printf: @nums.sort.join: ', ';
+
+ my Solution $solution = split-same-avg( @nums );
+
+ "Output: %s\n".printf: $solution[ 0 ] ?? 'True' !! 'False';
+
+ if $VERBOSE && $solution[ 0 ]
+ {
+ "\nWe can split the given array into (%s) and (%s)\n".printf:
+ $solution[ 1 ].keys.sort.join( ', ' ),
+ $solution[ 2 ].keys.sort.join( ', ' );
+
+ "The average of each of these arrays is { $solution[ 3 ] }".put;
+ }
+}
+
+#===============================================================================
+multi sub MAIN() # No input: run the test suite
+#===============================================================================
+{
+ run-tests();
+}
+
+#-------------------------------------------------------------------------------
+sub split-same-avg( List:D[Int:D] $nums --> Solution:D )
+#-------------------------------------------------------------------------------
+{
+ if $nums.elems >= 2
+ {
+ my Bag[Int] $univ = Bag[Int].new: $nums.map: { .Int };
+
+ # Prefer the solution in which the partitions are closest in size (see
+ # Notes 2 above)
+
+ for $nums.combinations: (1 .. ($nums.elems / 2).floor).reverse
+ {
+ my Int @comb = .map: { .Int };
+ my Bag[Int] $part1 = Bag[Int].new: @comb;
+ my Bag[Int] $part2 = $univ (-) $part1;
+ my Rat $avg1 = ([+] $part1.keys) / $part1.elems;
+ my Rat $avg2 = ([+] $part2.keys) / $part2.elems;
+
+ return [True, $part1, $part2, $avg1] if $avg1 == $avg2;
+ }
+ }
+
+ return [False, Bag, Bag, Rat];
+}
+
+#-------------------------------------------------------------------------------
+sub run-tests()
+#-------------------------------------------------------------------------------
+{
+ 'Running the test suite'.put;
+
+ for test-data.lines -> Str $line
+ {
+ my Str ($test-name, $input, @output) = $line.split: / \| /;
+
+ $test-name ~~ s/ \s+ $ //; # Trim whitespace
+ $input ~~ s/ \s+ $ //;
+ @output[ 0 ] ~~ s/ \s+ $ //;
+
+ my Int @nums = $input\.split( / \, \s* / ).map: { .Int };
+ my Bool $expected = @output[ 0 ] eq 'True' ?? True !! False;
+ my Solution $got = split-same-avg( @nums );
+
+ is $got[ 0 ], $expected, $test-name;
+
+ if $got[ 0 ] && $expected
+ {
+ my Bag[Int] $part1 = Bag[Int].new:
+ @output[ 1 ].split( / \, \s* / ).map: { .Int };
+ my Bag[Int] $part2 = Bag[Int].new:
+ @output[ 2 ].split( / \, \s* / ).map: { .Int };
+ my Rat $avg = @output[ 3 ].Rat;
+
+ ok $got[ 1 ] ≡ $part1, "$test-name: partition 1";
+ ok $got[ 2 ] ≡ $part2, "$test-name: partition 2";
+ is $got[ 3 ], $avg, "$test-name: average";
+ }
+ }
+
+ done-testing;
+}
+
+#-------------------------------------------------------------------------------
+sub USAGE()
+#-------------------------------------------------------------------------------
+{
+ my Str $usage = $*USAGE;
+
+ $usage ~~ s:g/ ($*PROGRAM-NAME) /raku $0/;
+
+ $usage.put;
+}
+
+#-------------------------------------------------------------------------------
+sub test-data( --> Str:D )
+#-------------------------------------------------------------------------------
+{
+ # The specific solution to Example 1 has been changed in accordance with the
+ # algorithm used in split-same-avg()
+
+ return q:to/END/;
+ Example 1| 1, 2, 3, 4, 5, 6, 7, 8|True | 1, 2, 7, 8| 3, 4, 5, 6| 4.5
+ Example 2| 1, 3 |False
+ Negatives|-4,-2,-3 |True |-3 |-4,-2 |-3
+ Mixed 1 |-7, 5, 0, 9,12,-1, 4, 6|True |-7, 4, 5,12|-1, 0, 6, 9| 3.5
+ Mixed 2 |-7, 5, 0, 9,12,-1, 4, 5|False
+ Same | 4, 4 |True | 4 | 4 | 4
+ Zeros | 0, 0, 0 |True | 0 | 0, 0 | 0
+ One |42 |False
+ END
+}
+
+################################################################################