aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohammad Sajid Anwar <Mohammad.Anwar@yahoo.com>2024-01-02 11:16:47 +0000
committerGitHub <noreply@github.com>2024-01-02 11:16:47 +0000
commitca2a93e05c838ef0bdd86b01c8def081c1586088 (patch)
tree14d6e1c70a442e2aa696e9a0b8764526f91111ea
parentd406d35523e9972dc948f8bc7e7d802b56ed2714 (diff)
parent139908fe65d29944783accaa97e86d13a2e81515 (diff)
downloadperlweeklychallenge-club-ca2a93e05c838ef0bdd86b01c8def081c1586088.tar.gz
perlweeklychallenge-club-ca2a93e05c838ef0bdd86b01c8def081c1586088.tar.bz2
perlweeklychallenge-club-ca2a93e05c838ef0bdd86b01c8def081c1586088.zip
Merge pull request #9335 from ajmetz/new-branch
Challenge 249 - Committing andrew_mehta folder containing README, a P…
-rw-r--r--challenge-249/andrew_mehta/README1
-rwxr-xr-xchallenge-249/andrew_mehta/perl/Ch_1.pm500
-rw-r--r--challenge-249/andrew_mehta/perl/lib/CodeBoilerplate.pm44
-rw-r--r--challenge-249/andrew_mehta/perl/lib/TestBoilerplate.pm42
-rwxr-xr-xchallenge-249/andrew_mehta/perl/t2/Ch_1.t312
5 files changed, 899 insertions, 0 deletions
diff --git a/challenge-249/andrew_mehta/README b/challenge-249/andrew_mehta/README
new file mode 100644
index 0000000000..45287ff20d
--- /dev/null
+++ b/challenge-249/andrew_mehta/README
@@ -0,0 +1 @@
+Solution by Andrew Mehta. \ No newline at end of file
diff --git a/challenge-249/andrew_mehta/perl/Ch_1.pm b/challenge-249/andrew_mehta/perl/Ch_1.pm
new file mode 100755
index 0000000000..193e77dbad
--- /dev/null
+++ b/challenge-249/andrew_mehta/perl/Ch_1.pm
@@ -0,0 +1,500 @@
+use Object::Pad 0.807;
+use strict;
+use warnings;
+
+package EqualPairs v1.0.0;
+class EqualPairs {
+
+ use File::Basename;
+ use lib dirname(__FILE__)."/lib";
+ use CodeBoilerplate;
+ use Data::Dumper qw(Dumper); # Used in input validation check warnings.
+ use Pod::Text::Color;
+
+=pod Name, Synopsis, Description
+
+=encoding utf8
+
+=head1 NAME
+
+EqualPairs - Additional Class / Package within Ch_1.pm file.
+
+=cut
+
+=head1 SYNOPSIS
+
+ my @input = (3, 2, 3, 2, 2, 2);
+ my $answer_to_task_1 = EqualPairs->new->input(@input)->pretty_output;
+
+=cut
+
+=head1 DESCRIPTION
+
+For the construction of new EqualPairs object instances,
+used in providing the answer
+to the Perl Weekly Challenge 249
+Task 1 (set 25th December 2023).
+
+Package omits...
+
+ 1;
+
+...at the end, as this is not needed
+with feature bundles v5.37 or higher,
+as documented at
+L<https://perldoc.perl.org/functions/require>.
+
+=cut
+
+=head1 METHODS
+
+=over
+
+=item new(input => $array_reference);
+
+ # With default empty input:
+ my $equal_pairs_object = EqualPairs->new;
+
+ # With input provided as array reference:
+ my $array_reference = [3, 2, 3, 2, 2, 2];
+ my $equal_pairs_object = EqualPairs->new(input => $array_reference);
+
+Constructs and returns a new object instance.
+Optionally, the constructor
+can set the input object attribute.
+
+=cut
+
+ field $input :param = [];
+
+=item output;
+
+ my @empty_array = EqualPairs->new->output;
+ my @array_of_array_references = EqualPairs->new->input(3, 2, 3, 2, 2, 2)->output;
+
+Returns an array, containing an array reference
+for each equal pair found during input processing.
+
+If no pairs of equal numbers are found,
+or no input has been set yet,
+will return an empty array.
+
+=cut
+
+ field @output :reader = ();
+
+ my $new_line = "\n";
+ my $line_reference_prefix = 'Reported';
+
+ method $filter_input {
+
+ # Initial Values:
+ my $filtered = [];
+ my $changes = 0;
+ my $array_reference = $input
+ && (
+ (ref $input) eq 'ARRAY'
+ );
+
+ # Filter Out Undef:
+ push $filtered->@* , map {
+ if (defined $ARG) {
+ $ARG;
+ }
+ else {
+ $changes++;
+ ();
+ };
+ } $input->@*
+ if $array_reference;
+
+ # Output:
+ $input = $changes? $filtered:
+ $input;
+ return $self;
+ }
+
+ method $validate_input {
+
+ # Initial Values:
+ my @errors = ();
+ my $error_count = 0;
+ local $SIG{__WARN__} = sub {
+ push @errors, sprintf('[%s] - %s', ++$error_count, shift);
+ };
+ my $error_text = {
+
+ intro => $new_line.'Please address these errors and try again:'.$new_line,
+
+ pod => 'Printing Plain Old Documentation below '.
+ 'should it prove helpful...'.$new_line,
+
+ input_false => 'No value found '.
+ "for object instance's input field / object attribute. ".
+ $line_reference_prefix,
+
+ expected_array_ref => 'Expected input to be an array reference.'.$new_line.
+ 'Found ref to return "%s".'.$new_line.
+ 'When dumped with Data::Dumper, input is as follows:'.$new_line.
+ '%s'.
+ $line_reference_prefix,
+
+ empty => 'Input array reference was found to be empty, '.
+ 'and needs to be populated with digits to proceed. '.
+ $line_reference_prefix,
+
+ not_even => 'Expected an even number of elements in the list of digits '.
+ 'and found %s element%s. '.
+ $line_reference_prefix,
+
+ not_all_integers => 'Expected input array reference to contain only integer digits.'.$new_line.
+ 'When dumped with Data::Dumper, input is as follows:'.$new_line.
+ '%s'.
+ $line_reference_prefix,
+
+ plural => 's',
+
+ singular => q{},
+
+ exit_reason => 'Exiting due to %s error%s. '.
+ $line_reference_prefix,
+
+ };
+
+
+ # Regular Expressions:
+
+ my $matches_integer = qr/^\p{Digit}+$/; # Does not allow decimal dots nor Roman Numerals.
+
+
+ # Definitions:
+
+ my $array_reference = $input
+ && (
+ (ref $input) eq 'ARRAY'
+ );
+
+ my $contains_items = $array_reference
+ && $input->@*;
+
+ my $even_number_of_items = $contains_items
+ && !( # Negated
+ (scalar $input->@*) % 2
+ );
+
+ my $all_integers = $contains_items
+ && scalar $input->@* == scalar map {
+ $ARG =~ $matches_integer? $ARG:
+ ();
+ } $input->@*;
+
+
+ # Checks:
+
+ warn $error_text->{'input_false'}
+ unless $input;
+
+ warn sprintf($error_text->{'expected_array_ref'}, (ref $input) , Dumper($input),)
+ unless $array_reference;
+
+ warn $error_text->{'empty'}
+ unless $contains_items;
+
+ warn sprintf(
+
+ $error_text->{'not_even'}, scalar $input->@*,
+
+ scalar $input->@* == 1? $error_text->{'singular'}:
+ $error_text->{'plural'},
+
+ )
+ unless $even_number_of_items;
+
+ warn sprintf($error_text->{'not_all_integers'}, Dumper($input),)
+ unless $all_integers;
+
+
+
+ # Output:
+
+ if (@errors) {
+
+ say join $new_line, ($error_text->{'intro'}, @errors);
+ say $error_text->{'pod'};
+
+ Pod::Text::Color->new->parse_from_file(__FILE__);
+
+ die sprintf(
+
+ $error_text->{'exit_reason'}, scalar @errors,
+
+ (scalar @errors == 1)? $error_text->{'singular'}:
+ $error_text->{'plural'},
+
+ );
+ };
+
+ return $self;
+
+ }
+
+ method $process_input {
+
+ # Initial Values:
+ my @equal_pairs = ();
+ my @sorted_input = sort {$a <=> $b} $input->@*;
+ my @full_range_of_input = (0..$#sorted_input);
+
+ # Processing:
+ for (@full_range_of_input) {
+
+ last if ($#sorted_input < 1);
+
+ my ($a, $b) = (shift @sorted_input, shift @sorted_input);
+ my $equal_pair = $a == $b? [$a, $b]:
+ undef;
+
+ if ($equal_pair) {
+ push @equal_pairs , $equal_pair;
+ }
+ else {
+ unshift @sorted_input , $b;
+ };
+
+ };
+
+ # Output:
+ @output = @equal_pairs;
+ return $self;
+
+ }
+
+=item input(@array);
+
+ # Set input via array indirectly:
+ my @array = (3, 2, 3, 2, 2, 2);
+ my $equal_pairs_object = EqualPairs->new->input(@array);
+
+ # Set input via array directly:
+ my $equal_pairs_object = EqualPairs->new->input(3, 2, 3, 2, 2, 2);
+
+Returns the object instance for method chaining.
+Requires that a list of values be provided as input,
+and that the list adhere to validation rules,
+or the script will be aborted/die.
+
+To be valid, input must be an even numbered list of integer digits.
+
+Automatically processes the input,
+and sets the L<"output"|/output;> object attribute.
+
+=cut
+
+ method input (@params) {
+ $input = @params? \@params:
+ $input;
+ return $self->$filter_input->$validate_input->$process_input;
+ }
+
+=item pretty_output;
+
+ say EqualPairs->new->input(3, 2, 3, 2, 2, 2)->pretty_output;
+
+Returns a string that can be displayed.
+Uses the values of the object instance's output object attribute
+(as can be obtained via the L<"output"|/output;> getter method)
+to generate a friendly output message intended for screen display,
+that lists the equal pairs the script has found after processing the input,
+or states no equal pairs were found.
+
+=back
+
+=cut
+
+ method pretty_output {
+
+ # Initial Values:
+ my $first = 1;
+ my $text = {
+ leader => 'Here are your equal pairs:'.$new_line.
+ 'Output: ',
+ blank => 'No equal pairs found.',
+ };
+
+ # Processing:
+ my $pretty_output = @output? $text->{'leader'}:
+ $text->{'blank'};
+
+ foreach my $pair (@output) {
+
+ $pretty_output .= ','
+ unless $first;
+ $first = undef if $first;
+ $pretty_output .= '('.$pair->[0].','.$pair->[1].')';
+
+ }
+
+ # Output:
+ return $pretty_output;
+
+ }
+
+=head1 AUTHOR
+
+Andrew Mehta
+
+=cut
+
+}
+
+package Ch_1 v1.0.0;
+class Ch_1 {
+ use File::Basename;
+ use lib dirname(__FILE__)."/lib";
+ use CodeBoilerplate;
+
+=pod Name, Version, Synopsis, Description
+
+=encoding utf8
+
+=head1 NAME
+
+Ch_1 - Perl Weekly Challenge 249 - Task 1 (Set 25th December 2023).
+
+=head1 VERSION
+
+v1.0.0
+
+=cut
+
+=head1 SYNOPSIS
+
+ # Run at the command line with input:
+ perl ./Ch_1.pm 3 2 3 2 2 2
+
+ # Use Perl Module:
+ use Ch_1;
+ my @input = (3, 2, 3, 2, 2, 2);
+ my $answer_to_task_1 = Ch_1->answer(@input);
+ my @equal_pairs = Ch_1->answer_data(@input);
+
+=head1 DESCRIPTION
+
+Contains L<"answer"|/answer(@array);>
+and L<"answer_data"|/answer_data(@array);> methods
+to the Perl Weekly Challenge 249 Task 1
+(set 25th December 2023).
+When executed (ran from the command line),
+the L<"answer"|/answer(@array);> method is ran,
+and its return value output to C<STDOUT>.
+
+Alternatively, the script can be used as a Perl Module,
+and the L<"answer"|/answer(@array);>
+and L<"answer_data"|/answer_data(@array);> methods
+invoked directly, returning a string for output
+and an array of array references for data manipulation,
+respectively.
+
+Package omits...
+
+ 1;
+
+...at the end, as this is not needed
+with feature bundles v5.37 or higher,
+as documented at
+L<https://perldoc.perl.org/functions/require>.
+
+=cut
+
+=head1 CLASS METHODS
+
+=over
+
+=item answer(@array);
+
+ use Ch_1;
+ my @input = (3, 2, 3, 2, 2, 2);
+ my $answer_to_task_1 = Ch_1->answer(@input);
+
+Outputs the answer to
+Perl Weekly Challenge 249 Task 1
+(set 25th December 2023).
+Takes a list consisting of an even number of digits as input.
+Returns a string containing output messages.
+
+=back
+
+=cut
+
+ method answer :common (@input) {
+ return EqualPairs->new->input(@input)->pretty_output;
+ }
+
+=over
+
+=item answer_data(@array);
+
+ use Ch_1;
+ my @input = (3, 2, 3, 2, 2, 2);
+ my @equal_pairs = Ch_1->answer_data(@input);
+
+Takes a list consisting of an even number of digits as input.
+
+Returns an array of array references,
+where each array reference is a pair of equal integers.
+This is the underlaying output data that
+is used in the display-friendly L<"answer"|/answer(@array);>.
+
+If no pairs of equal numbers are found,
+will return an empty array.
+
+
+=back
+
+=cut
+
+ method answer_data :common (@input) {
+ return EqualPairs->new->input(@input)->output;
+ }
+
+ say Ch_1->answer(@ARGV) unless caller; # If you omit the class name (Ch_1-> or __PACKAGE__->),
+ # @input will be missing the first @ARGV value
+ # - presumably shifted off to $self by Object::Pad.
+
+=head1 AUTHOR
+
+Andrew Mehta
+
+=cut
+
+}
+
+__END__
+
+Task 1: Equal Pairs
+Submitted by: Mohammad S Anwar
+
+You are given an array of integers with even number of elements.
+
+Write a script to divide the given array into equal pairs such that:
+
+a) Each element belongs to exactly one pair.
+b) The elements present in a pair are equal.
+
+=================
+
+Example 1
+
+Input: @ints = (3, 2, 3, 2, 2, 2)
+Output: (2, 2), (3, 3), (2, 2)
+
+There are 6 elements in @ints.
+They should be divided into 6 / 2 = 3 pairs.
+@ints is divided into the pairs (2, 2), (3, 3), and (2, 2) satisfying all the conditions.
+
+Example 2
+
+Input: @ints = (1, 2, 3, 4)
+Output: ()
+
+There is no way to divide @ints 2 pairs such that the pairs satisfy every condition.
diff --git a/challenge-249/andrew_mehta/perl/lib/CodeBoilerplate.pm b/challenge-249/andrew_mehta/perl/lib/CodeBoilerplate.pm
new file mode 100644
index 0000000000..8f1e8cc6d6
--- /dev/null
+++ b/challenge-249/andrew_mehta/perl/lib/CodeBoilerplate.pm
@@ -0,0 +1,44 @@
+package CodeBoilerplate;
+
+use strict;
+use warnings;
+use utf8;
+
+my $feature_bundle;
+my $version_number_to_use;
+
+BEGIN {
+ $version_number_to_use = '5.38';
+ $feature_bundle = ':'.$version_number_to_use;
+};
+
+use feature "$feature_bundle";
+
+use Import::Into;
+use English;
+
+our $VERSION = 'v2.0.0';
+
+sub import {
+
+ # Initial Variables:
+ my $calling_module_level_depth = 1;
+
+ # Processing / Declaring what to import:
+ $ARG ->import for qw(strict warnings utf8);
+ feature ->import ($feature_bundle);
+ English ->import::into ($calling_module_level_depth);
+
+ #UTF-8 the default on standard input and output:
+ binmode STDIN, ":encoding(UTF-8)";
+ binmode STDOUT, ":encoding(UTF-8)";
+ binmode STDERR, ":encoding(UTF-8)";
+
+}
+
+# Protect subclasses using AUTOLOAD
+sub DESTROY { }
+
+1;
+
+__END__ \ No newline at end of file
diff --git a/challenge-249/andrew_mehta/perl/lib/TestBoilerplate.pm b/challenge-249/andrew_mehta/perl/lib/TestBoilerplate.pm
new file mode 100644
index 0000000000..d45c1d8cc8
--- /dev/null
+++ b/challenge-249/andrew_mehta/perl/lib/TestBoilerplate.pm
@@ -0,0 +1,42 @@
+package TestBoilerplate;
+
+use CodeBoilerplate;
+use Import::Into;
+use Test::Output;
+use Test2::V0;
+use Test2::Tools::Compare;
+use Test2::Tools::Exception;
+
+our $VERSION = 'v2.0.0';
+
+sub import {
+
+ # Initial Variables:
+ my $calling_module_level_depth = 1;
+ my @compare_imports = qw{
+ is like isnt unlike
+ match mismatch validator
+ hash array bag object meta number float rounded within string subset bool
+ in_set not_in_set check_set
+ item field call call_list call_hash prop check all_items all_keys all_vals all_values
+ etc end filter_items
+ T F D DF E DNE FDNE U L
+ event fail_events
+ exact_ref
+ };
+
+ # Processing / Declaring what to import:
+ CodeBoilerplate ->import::into ($calling_module_level_depth);
+ Test::Output ->import::into ($calling_module_level_depth);
+ Test2::V0 ->import::into ($calling_module_level_depth);
+ Test2::Tools::Compare ->import::into ($calling_module_level_depth, @compare_imports);
+ Test2::Tools::Exception ->import::into ($calling_module_level_depth);
+
+}
+
+# Protect subclasses using AUTOLOAD
+sub DESTROY { }
+
+1;
+
+__END__
diff --git a/challenge-249/andrew_mehta/perl/t2/Ch_1.t b/challenge-249/andrew_mehta/perl/t2/Ch_1.t
new file mode 100755
index 0000000000..e4b7235133
--- /dev/null
+++ b/challenge-249/andrew_mehta/perl/t2/Ch_1.t
@@ -0,0 +1,312 @@
+
+# Custom Libraries:
+use Path::Tiny;
+use lib path(__FILE__)->parent->parent->realpath->stringify;
+use lib path(__FILE__)->parent->sibling('lib')->realpath->stringify;
+
+# Standard Test Boilerplate:
+use TestBoilerplate;
+
+# Specific Modules used:
+use Ch_1;
+
+=pod Name, Version, Synopsis, Description
+
+=encoding utf8
+
+=head1 NAME
+
+Ch_1.t Test File.
+
+=head1 VERSION
+
+v1.0.0
+
+=cut
+
+our $VERSION = 'v1.0.0';
+
+=head1 SYNOPSIS
+
+ yath -v # Will automatically run tests found in the ./t2 folder ( such as this test ), in verbose mode.
+
+=head1 DESCRIPTION
+
+This unit test, tests the C<Ch_1.pm> Perl modulino,
+originally made for the Perl Weekly Challenge 249
+Task 1 (set 25th December 2023).
+
+It tests for the C<Ch_1> class
+and that class' C<answer> and C<answer_data> methods;
+then tests the output of these methods,
+given a variety of input test data
+and output expectations.
+
+For each piece of provided test data,
+this unit test
+checks for errors,
+and if the script dies or lives;
+and then checks for output,
+and if output is as expected.
+Finally it checks that
+the challenge rules have been met:
+
+=over
+
+=item 1
+
+Each element belongs to exactly one pair.
+
+=item 2
+
+The elements present in a pair are equal.
+
+=back
+
+Both Input Data and Output Expectations
+are set in a single array
+within the source code
+of this unit test script.
+
+=cut
+
+# Initial Values:
+my $text = {
+ prefix => '[Test Case %04d] - %s - %s.',
+ result_prefix => "Here are your equal pairs:\nOutput: ",
+ no_pairs_result => 'No equal pairs found',
+ true => 'Output is true',
+ 'dies' => 'Programme died',
+ delivers_result => 'Programme delivered result and did not die',
+ error => 'Error(s) found',
+ no_error => 'No Error(s) found',
+ address_errors => 'address these errors',
+ expected => 'Contained expected output - "%s"',
+ class => 'Class Name As Expected',
+ methods => 'Expected Methods Present',
+ two => 'Pair %d consists of two values: (%d,%d)',
+ frequency => 'Each input element of "%d" that became paired (%d out of %d) belongs to exactly one pair',
+ equal => 'Pair %d elements are equal: (%d,%d)',
+};
+my $error = {
+ uneven => '[1] - Expected an even number of elements',
+ non_integer => '[1] - Expected input array reference to contain only integer digits',
+ empty => '[1] - Input array reference was found to be empty',
+ die_message => 'Exiting due to',
+};
+my $value_delimiter = ", ";
+my $matches_die_message = qr/\Q$error->{'die_message'}/;
+my $matches_error = qr/\Q$text->{'address_errors'}/;
+my $matches_result = qr/(
+ \Q$text->{'result_prefix'}\E
+ |
+ \Q$text->{'no_pairs_result'}\E
+ )/x;
+my $test_name = sub { sprintf($text->{prefix}, @ARG) };
+my $test_count = 1;
+my $expected_class = 'Ch_1';
+my @expected_methods = qw(answer answer_data);
+
+# Test Data:
+my @test_data = (
+ # Test Name # Input: #Expected Output
+ 'Odd Number of Elements' => [qw(1 2 3)] => $error->{'uneven'},
+ 'Letter Elements' => [qw(a a a b b b)] => $error->{'non_integer'},
+ 'Digits and Letters' => [qw(1 a 1 b 1 b)] => $error->{'non_integer'},
+ 'Words' => [qw(cat sat mat different)] => $error->{'non_integer'},
+ 'No Equal Integer Pairs' => [qw(1 2 3 4)] => $text->{'no_pairs_result'},
+ 'No Elements' => [qw()] => $error->{'empty'},
+ 'One Large Digit' => [qw(999999999)] => $error->{'uneven'},
+ 'Lots Of Large Digits 1' => [qw(
+ 112 16648 19999
+ 9999999 9999999
+ 112 88888888888
+ 88888888888 112
+ 19999
+ )] => 'Output: (112,112),(19999,19999),(9999999,9999999),(88888888888,88888888888)',
+ 'Lots Of Large Digits 2' => [qw(
+ 112 16648 19999
+ 9999999 9999999
+ 112 88888888888
+ 88888888888 112
+ 19999 233333556
+ )] => $error->{'uneven'},
+ 'End Odd List With Undef' => [qw(
+ 112 16648 19999
+ 9999999 9999999
+ 112 88888888888
+ 88888888888 112
+ 19999
+ ),undef] => 'Output: (112,112),(19999,19999),(9999999,9999999),(88888888888,88888888888)',
+ 'End Even List With Undef' => [qw(
+ 112 16648 19999
+ 9999999 9999999
+ 112 88888888888
+ 88888888888 112
+ 19999 233333556
+ ),undef] => $error->{'uneven'},
+ 'Odd List With '.
+ 'Undef In Middle' => [qw(
+ 112 16648 19999
+ 9999999 9999999
+ 112), undef, qw(
+ 88888888888
+ 88888888888 112
+ 19999
+ )] => 'Output: (112,112),(19999,19999),(9999999,9999999),(88888888888,88888888888)',
+ 'Even List '.
+ 'With Undef In Middle' => [qw(
+ 112 16648 19999
+ 9999999 9999999
+ 112), undef, qw(
+ 88888888888
+ 88888888888 112
+ 19999 233333556
+ )] => $error->{'uneven'},
+ 'Four Byte Unicode 1' => [qw(šŸƒ‘ šŸƒ‘)] => $error->{'non_integer'},
+ 'Four Byte Unicode 2' => [qw(šŸƒ‘ 1)] => $error->{'non_integer'},
+ 'Four Byte Unicode 3' => [qw(šŸƒ‘ šŸƒ‘ 1 1)] => $error->{'non_integer'},
+ 'Odd List With '.
+ 'All Elements Undef' => [undef,undef,undef] => $error->{'empty'},
+ 'Even List With '.
+ 'All Elements Undef' => [undef,undef,undef,undef] => $error->{'empty'},
+ 'Single Digits Test 1' => [qw( 1 2 3 4 4 4 5 6 )] => 'Output: (4,4)',
+ 'Single Digits Test 2' => [qw( 1 2 3 4 4 4 5 6 5 6 )] => 'Output: (4,4),(5,5),(6,6)',
+ 'Non-single Digits Test 1' => [qw(
+ 01 02 33 44 44 44
+ 5555 66 5555 66 01 01
+ )] => 'Output: (01,01),(44,44),(66,66),(5555,5555)',
+ 'Many Similar Numbers 1' => [qw(
+ 1 1 1 1 1 1 1 1
+ 23 23 23 23 23
+ 2023 2023 2023
+ 400000 400000
+ 400000 400000
+ 400000 400000
+ 9999999999999
+ 9999999999999
+ )] => 'Output: (1,1),(1,1),(1,1),(1,1),'.
+ '(23,23),(23,23),(2023,2023),'.
+ '(400000,400000),(400000,400000),(400000,400000),'.
+ '(9999999999999,9999999999999)',
+ 'Nonsense' => [qw( gfhdsjsahsgshhjsh )] => $text->{'address_errors'},
+);
+
+# Test Processing:
+
+isa_ok(
+ Ch_1 => [$expected_class],
+ $test_name->($test_count++, $text->{'class'}, $expected_class)
+);
+
+can_ok(
+ Ch_1 => [@expected_methods],
+ $test_name->($test_count++, $text->{'methods'}, join($value_delimiter, @expected_methods))
+);
+
+# Test Data Processing:
+
+for my ($name, $input, $expected_string) (@test_data) {
+
+ my $matches_expected = qr/\Q$expected_string/;
+ my $output = combined_from(
+ sub {
+ my $successful_output = undef;
+ warn $successful_output
+ if
+ lives { $successful_output = Ch_1->answer($input->@*) }
+ && defined $successful_output;
+ }
+ );
+ my $delivers_result = 0;
+
+ if ($EVAL_ERROR) {
+ like(
+ $output => $matches_error,
+ $test_name->($test_count++, $name, $text->{'error'})
+ );
+
+ like(
+ $EVAL_ERROR => $matches_die_message,
+ $test_name->($test_count++, $name, $text->{'dies'})
+ );
+ }
+ else {
+ unlike(
+ $output => $matches_error, #unlike
+ $test_name->($test_count++, $name, $text->{'no_error'}) #unlike
+ );
+ $delivers_result =
+ like(
+ $output => $matches_result,
+ $test_name->($test_count++, $name, $text->{'delivers_result'})
+ );
+ };
+
+ is(
+ $output => T(),
+ $test_name->($test_count++, $name, $text->{'true'})
+ );
+
+ like(
+ $output => $matches_expected,
+ $test_name->($test_count++, $name, sprintf($text->{'expected'}, $expected_string))
+ );
+
+ # Test Challenge Rules:
+ if ($delivers_result) {
+
+ # Initial Values:
+ my @output_data = Ch_1->answer_data($input->@*);
+
+ if (@output_data) {
+
+ # Initial Values:
+ my %input_frequency = ();
+ my %output_frequency = ();
+ my @flattened_output_data = ();
+ push @flattened_output_data , $ARG->@* for @output_data;
+ my $pair_count = 1;
+
+ # Process Frequencies:
+ $input_frequency{$ARG}++ for map {defined $ARG? $ARG:()} $input->@*;
+ $output_frequency{$ARG}++ for map {defined $ARG? $ARG:()} @flattened_output_data;
+
+ # Test Processing:
+
+ # a) Each element belongs to exactly one pair.
+ for my $input_item (sort {$a <=> $b} keys %input_frequency) {
+ exists $output_frequency{$input_item}
+ && ok(
+ $output_frequency{$input_item} <= $input_frequency{$input_item} <= $output_frequency{$input_item} + 1,
+ $test_name->($test_count++, $name, sprintf($text->{'frequency'}, $input_item, $output_frequency{$input_item}, $input_frequency{$input_item})),
+ );
+ };
+
+ # b) The elements present in a pair are equal.
+ for my $pair (@output_data) {
+ is(
+ scalar $pair->@* => 2,
+ $test_name->($test_count++, $name, sprintf($text->{'two'}, $pair_count, $pair->@*)),
+ )
+ && is(
+ $pair->[0] => $pair->[1],
+ $test_name->($test_count++, $name, sprintf($text->{'equal'}, $pair_count++, $pair->@*)),
+ );
+ };
+
+ };
+
+ };
+
+}
+
+done_testing();
+
+=head1 AUTHOR
+
+Andrew Mehta
+
+=cut
+
+__END__