aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPerlMonk-Athanasius <PerlMonk.Athanasius@gmail.com>2025-08-13 23:11:18 +1000
committerPerlMonk-Athanasius <PerlMonk.Athanasius@gmail.com>2025-08-13 23:11:18 +1000
commit35a2f634f48c6fca3f11a504d3345306b2c28a50 (patch)
treee74611c5e280699299bcc24c53720473f4dcd418
parent3f0c25ac7a8089ff3d921c6e4926ff88ebd806cd (diff)
downloadperlweeklychallenge-club-35a2f634f48c6fca3f11a504d3345306b2c28a50.tar.gz
perlweeklychallenge-club-35a2f634f48c6fca3f11a504d3345306b2c28a50.tar.bz2
perlweeklychallenge-club-35a2f634f48c6fca3f11a504d3345306b2c28a50.zip
Perl & Raku solutions to Tasks 1 & 2 for Week 334
-rw-r--r--challenge-334/athanasius/perl/ch-1.pl232
-rw-r--r--challenge-334/athanasius/perl/ch-2.pl257
-rw-r--r--challenge-334/athanasius/raku/ch-1.raku176
-rw-r--r--challenge-334/athanasius/raku/ch-2.raku244
4 files changed, 909 insertions, 0 deletions
diff --git a/challenge-334/athanasius/perl/ch-1.pl b/challenge-334/athanasius/perl/ch-1.pl
new file mode 100644
index 0000000000..13cd72e30a
--- /dev/null
+++ b/challenge-334/athanasius/perl/ch-1.pl
@@ -0,0 +1,232 @@
+#!perl
+
+################################################################################
+=comment
+
+Perl Weekly Challenge 334
+=========================
+
+TASK #1
+-------
+*Range Sum*
+
+Submitted by: Mohammad Sajid Anwar
+
+You are given a list integers and pair of indices..
+
+Write a script to return the sum of integers between the given indices (inclu-
+sive).
+
+Example 1
+
+ Input: @ints = (-2, 0, 3, -5, 2, -1), $x = 0, $y = 2
+ Output: 1
+
+ Elements between indices (0, 2) => (-2, 0, 3)
+ Range Sum: (-2) + 0 + 3 => 1
+
+Example 2
+
+ Input: @ints = (1, -2, 3, -4, 5), $x = 1, $y = 3
+ Output: -3
+
+ Elements between indices (1, 3) => (-2, 3, -4)
+ Range Sum: (-2) + 3 + (-4) => -3
+
+Example 3
+
+ Input: @ints = (1, 0, 2, -1, 3), $x = 3, $y = 4
+ Output: 2
+
+ Elements between indices (3, 4) => (-1, 3)
+ Range Sum: (-1) + 3 => 2
+
+Example 4
+
+ Input: @ints = (-5, 4, -3, 2, -1, 0), $x = 0, $y = 3
+ Output: -2
+
+ Elements between indices (0, 3) => (-5, 4, -3, 2)
+ Range Sum: (-5) + 4 + (-3) + 2 => -2
+
+Example 5
+
+ Input: @ints = (-1, 0, 2, -3, -2, 1), $x = 0, $y = 2
+ Output: 1
+
+ Elements between indices (0, 2) => (-1, 0, 2)
+ Range Sum: (-1) + 0 + 2 => 1
+
+=cut
+################################################################################
+
+#--------------------------------------#
+# Copyright © 2025 PerlMonk Athanasius #
+#--------------------------------------#
+
+#===============================================================================
+=comment
+
+Interface
+---------
+1. If no command-line arguments are given, the test suite is run. Otherwise:
+2. Indices x and y are entered on the command-line as named parameters, followed
+ by a non-empty list of integers.
+3. The first negative integer in the list (if any) must be preceded by "--" to
+ indicate that it is not a command-line flag.
+
+=cut
+#===============================================================================
+
+use v5.32; # Enables strictures
+use warnings;
+use Const::Fast;
+use Getopt::Long;
+use Regexp::Common qw( number );
+use Test::More;
+
+const my $DEBUG => 1;
+const my $USAGE => <<END;
+Usage:
+ perl $0 [-x[=UInt]] [-y[=UInt]] [<ints> ...]
+ perl $0
+
+ -x[=UInt] First index
+ -y[=UInt] Second index
+ [<ints> ...] A non-empty list of integers
+END
+#-------------------------------------------------------------------------------
+BEGIN
+#-------------------------------------------------------------------------------
+{
+ $| = 1;
+ print "\nChallenge 334, Task #1: Range Sum (Perl)\n\n";
+}
+
+#===============================================================================
+MAIN:
+#===============================================================================
+{
+ my $argc = scalar @ARGV;
+
+ if ($argc == 0)
+ {
+ run_tests();
+ }
+ elsif ($argc < 3)
+ {
+ error( "Expected 0 or 3+ command-line arguments, found $argc" );
+ }
+ else
+ {
+ my ($ints, $x, $y) = parse_command_line();
+
+ printf "Input: \@ints = (%s), \$x = $x, \$y = $y\n", join ', ', @$ints;
+
+ my $sum = find_range_sum( $ints, $x, $y );
+
+ print "Output: $sum\n";
+ }
+}
+
+#-------------------------------------------------------------------------------
+sub find_range_sum
+#-------------------------------------------------------------------------------
+{
+ my ($ints, $x, $y) = @_;
+
+ validate_args( $ints, $x, $y ) if $DEBUG;
+
+ my $sum = 0;
+
+ for my $i ($x .. $y)
+ {
+ $sum += $ints->[ $i ];
+ }
+
+ return $sum;
+}
+
+#-------------------------------------------------------------------------------
+sub parse_command_line
+#-------------------------------------------------------------------------------
+{
+ my ($x, $y);
+
+ GetOptions
+ (
+ 'x=i' => \$x,
+ 'y=i' => \$y
+
+ ) or error( 'Invalid command-line arguments' );
+
+ my @ints = @ARGV;
+
+ validate_args( \@ints, $x, $y );
+
+ return (\@ints, $x, $y);
+}
+
+#-------------------------------------------------------------------------------
+sub validate_args
+#-------------------------------------------------------------------------------
+{
+ my ($ints, $x, $y) = @_;
+
+ for (@$ints, $x, $y)
+ {
+ / ^ $RE{num}{int} $ /x
+ or error( qq["$_" is not a valid integer] );
+ }
+
+ $x >= 0 or error( 'x is negative' );
+ $y >= 0 or error( 'y is negative' );
+ $y >= $x or error( 'x is greater than y' );
+ scalar @$ints > 0 or error( 'The input list of integers is empty' );
+ $#$ints >= $y or error( 'y is too large for the list' );
+}
+
+#-------------------------------------------------------------------------------
+sub run_tests
+#-------------------------------------------------------------------------------
+{
+ print "Running the test suite\n";
+
+ while (my $line = <DATA>)
+ {
+ chomp $line;
+
+ my ($test_name, $ints_str, $x, $y, $expected) = split / \| /x, $line;
+
+ for ($test_name, $ints_str, $x, $y, $expected)
+ {
+ s/ ^ \s+ //x;
+ s/ \s+ $ //x;
+ }
+
+ my @ints = split / \s+ /x, $ints_str;
+ my $sum = find_range_sum( \@ints, $x, $y );
+
+ is $sum, $expected, $test_name;
+ }
+
+ done_testing;
+}
+
+#-------------------------------------------------------------------------------
+sub error
+#-------------------------------------------------------------------------------
+{
+ my ($message) = @_;
+
+ die "ERROR: $message\n$USAGE";
+}
+
+################################################################################
+
+__DATA__
+Example 1|-2 0 3 -5 2 -1|0|2| 1
+Example 2| 1 -2 3 -4 5 |1|3|-3
+Example 3| 1 0 2 -1 3 |3|4| 2
+Example 4|-5 4 -3 2 -1 0|0|3|-2
+Example 5|-1 0 2 -3 -2 1|0|2| 1
diff --git a/challenge-334/athanasius/perl/ch-2.pl b/challenge-334/athanasius/perl/ch-2.pl
new file mode 100644
index 0000000000..96501688da
--- /dev/null
+++ b/challenge-334/athanasius/perl/ch-2.pl
@@ -0,0 +1,257 @@
+#!perl
+
+################################################################################
+=comment
+
+Perl Weekly Challenge 334
+=========================
+
+TASK #2
+-------
+*Nearest Valid Point*
+
+Submitted by: Mohammad Sajid Anwar
+
+You are given current location as two integers: x and y. You are also given a
+list of points on the grid.
+
+A point is considered valid if it shares either the same x-coordinate or the
+same y-coordinate as the current location.
+
+Write a script to return the index of the valid point that has the smallest
+Manhattan distance to the current location. If multiple valid points are tied
+for the smallest distance, return the one with the lowest index. If no valid
+points exist, return -1.
+
+ The Manhattan distance between two points (x1, y1) and (x2, y2) is
+ calculated as: |x1 - x2| + |y1 - y2|
+
+Example 1
+
+ Input: $x = 3, $y = 4, @points ([1, 2], [3, 1], [2, 4], [2, 3])
+ Output: 2
+
+ Valid points: [3, 1] (same x), [2, 4] (same y)
+
+ Manhattan distances:
+ [3, 1] => |3-3| + |4-1| = 3
+ [2, 4] => |3-2| + |4-4| = 1
+
+ Closest valid point is [2, 4] at index 2.
+
+Example 2
+
+ Input: $x = 2, $y = 5, @points ([3, 4], [2, 3], [1, 5], [2, 5])
+ Output: 3
+
+ Valid points: [2, 3], [1, 5], [2, 5]
+
+ Manhattan distances:
+ [2, 3] => 2
+ [1, 5] => 1
+ [2, 5] => 0
+
+ Closest valid point is [2, 5] at index 3.
+
+Example 3
+
+ Input: $x = 1, $y = 1, @points ([2, 2], [3, 3], [4, 4])
+ Output: -1
+
+ No point shares x or y with (1, 1).
+
+Example 4
+
+ Input: $x = 0, $y = 0, @points ([0, 1], [1, 0], [0, 2], [2, 0])
+ Output: 0
+
+ Valid points: all of them
+
+ Manhattan distances:
+ [0, 1] => 1
+ [1, 0] => 1
+ [0, 2] => 2
+ [2, 0] => 2
+
+ Tie between index 0 and 1, pick the smaller index: 0
+
+Example 5
+
+ Input: $x = 5, $y = 5, @points ([5, 6], [6, 5], [5, 4], [4, 5])
+ Output: 0
+
+ Valid points: all of them
+ [5, 6] => 1
+ [6, 5] => 1
+ [5, 4] => 1
+ [4, 5] => 1
+
+ All tie, return the one with the lowest index: 0
+
+=cut
+################################################################################
+
+#--------------------------------------#
+# Copyright © 2025 PerlMonk Athanasius #
+#--------------------------------------#
+
+#===============================================================================
+=comment
+
+Assumption
+----------
+The x and y coordinates of the points in the given input list are all integers.
+
+Interface
+---------
+1. If no command-line arguments are given, the test suite is run. Otherwise:
+2. The x and y coordinates of the current location are entered on the command-
+ line, followed by a list of points. Each point is given as an x coordinate
+ followed by a y coordinate. All coordinates are integers.
+
+=cut
+#===============================================================================
+
+use v5.32; # Enables strictures
+use warnings;
+use Const::Fast;
+use List::Util qw( pairs );
+use Regexp::Common qw( number );
+use Test::More;
+
+const my $USAGE => <<END;
+Usage:
+ perl $0 <x> <y> [<points> ...]
+ perl $0
+
+ <x> The x-coordinate of the current location
+ <y> The y-coordinate of the current location
+ [<points> ...] An even-sized list of point coordinates in x y order
+END
+
+#-------------------------------------------------------------------------------
+BEGIN
+#-------------------------------------------------------------------------------
+{
+ $| = 1;
+ print "\nChallenge 334, Task #2: Nearest Valid Point (Perl)\n\n";
+}
+
+#===============================================================================
+MAIN:
+#===============================================================================
+{
+ my $argc = scalar @ARGV;
+
+ if ($argc == 0)
+ {
+ run_tests();
+ }
+ elsif ($argc % 2 == 1)
+ {
+ error( 'Expected an even number of command-line arguments, found ' .
+ $argc );
+ }
+ else
+ {
+ my ($x, $y, @coords) = @ARGV;
+
+ for ($x, $y, @coords)
+ {
+ / ^ $RE{num}{int} $ /x or error( qq["$_" is not a valid integer] );
+ }
+
+ my @points = pairs @coords;
+
+ printf "Input: \$x = $x, \$y = $y, \@points = (%s)\n",
+ join ', ', map { '[' . join( ', ', @$_ ) . ']' } @points;
+
+ my $index = nearest_valid_point( [ $x, $y ], \@points );
+
+ print "Output: $index\n";
+ }
+}
+
+#-------------------------------------------------------------------------------
+sub nearest_valid_point
+#-------------------------------------------------------------------------------
+{
+ my ($current, $points) = @_;
+ my $index = -1;
+ my $min_dist;
+
+ for my $i (0 .. $#$points)
+ {
+ my $point = $points->[ $i ];
+ my $manhattan_dist;
+
+ if ($point->[ 0 ] == $current->[ 0 ])
+ {
+ $manhattan_dist = abs( $point->[ 1 ] - $current->[ 1 ] );
+ }
+ elsif ($point->[ 1 ] == $current->[ 1 ])
+ {
+ $manhattan_dist = abs( $point->[ 0 ] - $current->[ 0 ] );
+ }
+
+ if (defined $manhattan_dist &&
+ (!defined $min_dist || $min_dist > $manhattan_dist))
+ {
+ $index = $i;
+ $min_dist = $manhattan_dist;
+ }
+ }
+
+ return $index;
+}
+
+#-------------------------------------------------------------------------------
+sub run_tests
+#-------------------------------------------------------------------------------
+{
+ print "Running the test suite\n";
+
+ while (my $line = <DATA>)
+ {
+ chomp $line;
+
+ my ($test_name, $x, $y, $points_str, $expected) = split / \| /x, $line;
+
+ for ($test_name, $x, $y, $points_str, $expected)
+ {
+ s/ ^ \s+ //x;
+ s/ \s+ $ //x;
+ }
+
+ my @points;
+
+ for (split / \s* \; \s* /x, $points_str)
+ {
+ push @points, [ split / \s+ /x, $_ ];
+ }
+
+ my $index = nearest_valid_point( [ $x, $y ], \@points );
+
+ is $index, $expected, $test_name;
+ }
+
+ done_testing;
+}
+
+#-------------------------------------------------------------------------------
+sub error
+#-------------------------------------------------------------------------------
+{
+ my ($message) = @_;
+
+ die "ERROR: $message\n$USAGE";
+}
+
+################################################################################
+
+__DATA__
+Example 1|3|4|1 2; 3 1; 2 4; 2 3| 2
+Example 2|2|5|3 4; 2 3; 1 5; 2 5| 3
+Example 3|1|1|2 2; 3 3; 4 4 |-1
+Example 4|0|0|0 1; 1 0; 0 2; 2 0| 0
+Example 5|5|5|5 6; 6 5; 5 4; 4 5| 0
diff --git a/challenge-334/athanasius/raku/ch-1.raku b/challenge-334/athanasius/raku/ch-1.raku
new file mode 100644
index 0000000000..950ffce248
--- /dev/null
+++ b/challenge-334/athanasius/raku/ch-1.raku
@@ -0,0 +1,176 @@
+use v6d;
+
+################################################################################
+=begin comment
+
+Perl Weekly Challenge 334
+=========================
+
+TASK #1
+-------
+*Range Sum*
+
+Submitted by: Mohammad Sajid Anwar
+
+You are given a list integers and pair of indices..
+
+Write a script to return the sum of integers between the given indices (inclu-
+sive).
+
+Example 1
+
+ Input: @ints = (-2, 0, 3, -5, 2, -1), $x = 0, $y = 2
+ Output: 1
+
+ Elements between indices (0, 2) => (-2, 0, 3)
+ Range Sum: (-2) + 0 + 3 => 1
+
+Example 2
+
+ Input: @ints = (1, -2, 3, -4, 5), $x = 1, $y = 3
+ Output: -3
+
+ Elements between indices (1, 3) => (-2, 3, -4)
+ Range Sum: (-2) + 3 + (-4) => -3
+
+Example 3
+
+ Input: @ints = (1, 0, 2, -1, 3), $x = 3, $y = 4
+ Output: 2
+
+ Elements between indices (3, 4) => (-1, 3)
+ Range Sum: (-1) + 3 => 2
+
+Example 4
+
+ Input: @ints = (-5, 4, -3, 2, -1, 0), $x = 0, $y = 3
+ Output: -2
+
+ Elements between indices (0, 3) => (-5, 4, -3, 2)
+ Range Sum: (-5) + 4 + (-3) + 2 => -2
+
+Example 5
+
+ Input: @ints = (-1, 0, 2, -3, -2, 1), $x = 0, $y = 2
+ Output: 1
+
+ Elements between indices (0, 2) => (-1, 0, 2)
+ Range Sum: (-1) + 0 + 2 => 1
+
+=end comment
+################################################################################
+
+#--------------------------------------#
+# Copyright © 2025 PerlMonk Athanasius #
+#--------------------------------------#
+
+#===============================================================================
+=begin comment
+
+Interface
+---------
+1. If no command-line arguments are given, the test suite is run. Otherwise:
+2. Indices x and y are entered on the command-line as named parameters, followed
+ by a non-empty list of integers.
+3. If the first integer in the list is negative, it must be preceded by "--" to
+ indicate that it is not a command-line flag.
+
+=end comment
+#===============================================================================
+
+use Test;
+
+#-------------------------------------------------------------------------------
+BEGIN
+#-------------------------------------------------------------------------------
+{
+ "\nChallenge 334, Task #1: Range Sum (Raku)\n".put;
+}
+
+#===============================================================================
+multi sub MAIN
+(
+ UInt:D :$x, #= First index
+ UInt:D :$y where { $y >= $x }, #= Second index
+ #| A non-empty list of integers
+ *@ints where { .elems > 0 && .all ~~ Int:D && @ints.end >= $y }
+)
+#===============================================================================
+{
+ "Input: \@ints = (%s), \$x = $x, \$y = $y\n".printf: @ints.join: ', ';
+
+ my Int $sum = find-range-sum( @ints, $x, $y );
+
+ "Output: $sum".put;
+}
+
+#===============================================================================
+multi sub MAIN() # No input: run the test suite
+#===============================================================================
+{
+ run-tests();
+}
+
+#-------------------------------------------------------------------------------
+sub find-range-sum
+(
+ List:D[Int:D] $ints where { .elems > 0 },
+ UInt:D $x where { $ints.end >= $x },
+ UInt:D $y where { $ints.end >= $y && $y >= $x }
+--> Int:D
+)
+#-------------------------------------------------------------------------------
+{
+ return [+] $ints[ $x .. $y ];
+}
+
+#-------------------------------------------------------------------------------
+sub run-tests()
+#-------------------------------------------------------------------------------
+{
+ 'Running the test suite'.put;
+
+ for test-data.lines -> Str $line
+ {
+ my Str ($test-name, $ints-str, $x, $y, $expected) = $line.split: / \| /;
+
+ for $test-name, $ints-str, $x, $y, $expected
+ {
+ s/ ^ \s+ //;
+ s/ \s+ $ //;
+ }
+
+ my Int @ints = $ints-str.split( / \s+ /, :skip-empty ).map: { .Int };
+ my Int $sum = find-range-sum( @ints, $x.Int, $y.Int );
+
+ is $sum, $expected.Int, $test-name;
+ }
+
+ done-testing;
+}
+
+#-------------------------------------------------------------------------------
+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|-2 0 3 -5 2 -1|0|2| 1
+ Example 2| 1 -2 3 -4 5 |1|3|-3
+ Example 3| 1 0 2 -1 3 |3|4| 2
+ Example 4|-5 4 -3 2 -1 0|0|3|-2
+ Example 5|-1 0 2 -3 -2 1|0|2| 1
+ END
+}
+
+################################################################################
diff --git a/challenge-334/athanasius/raku/ch-2.raku b/challenge-334/athanasius/raku/ch-2.raku
new file mode 100644
index 0000000000..15d0919c90
--- /dev/null
+++ b/challenge-334/athanasius/raku/ch-2.raku
@@ -0,0 +1,244 @@
+use v6d;
+
+################################################################################
+=begin comment
+
+Perl Weekly Challenge 334
+=========================
+
+TASK #2
+-------
+*Nearest Valid Point*
+
+Submitted by: Mohammad Sajid Anwar
+
+You are given current location as two integers: x and y. You are also given a
+list of points on the grid.
+
+A point is considered valid if it shares either the same x-coordinate or the
+same y-coordinate as the current location.
+
+Write a script to return the index of the valid point that has the smallest
+Manhattan distance to the current location. If multiple valid points are tied
+for the smallest distance, return the one with the lowest index. If no valid
+points exist, return -1.
+
+ The Manhattan distance between two points (x1, y1) and (x2, y2) is
+ calculated as: |x1 - x2| + |y1 - y2|
+
+Example 1
+
+ Input: $x = 3, $y = 4, @points ([1, 2], [3, 1], [2, 4], [2, 3])
+ Output: 2
+
+ Valid points: [3, 1] (same x), [2, 4] (same y)
+
+ Manhattan distances:
+ [3, 1] => |3-3| + |4-1| = 3
+ [2, 4] => |3-2| + |4-4| = 1
+
+ Closest valid point is [2, 4] at index 2.
+
+Example 2
+
+ Input: $x = 2, $y = 5, @points ([3, 4], [2, 3], [1, 5], [2, 5])
+ Output: 3
+
+ Valid points: [2, 3], [1, 5], [2, 5]
+
+ Manhattan distances:
+ [2, 3] => 2
+ [1, 5] => 1
+ [2, 5] => 0
+
+ Closest valid point is [2, 5] at index 3.
+
+Example 3
+
+ Input: $x = 1, $y = 1, @points ([2, 2], [3, 3], [4, 4])
+ Output: -1
+
+ No point shares x or y with (1, 1).
+
+Example 4
+
+ Input: $x = 0, $y = 0, @points ([0, 1], [1, 0], [0, 2], [2, 0])
+ Output: 0
+
+ Valid points: all of them
+
+ Manhattan distances:
+ [0, 1] => 1
+ [1, 0] => 1
+ [0, 2] => 2
+ [2, 0] => 2
+
+ Tie between index 0 and 1, pick the smaller index: 0
+
+Example 5
+
+ Input: $x = 5, $y = 5, @points ([5, 6], [6, 5], [5, 4], [4, 5])
+ Output: 0
+
+ Valid points: all of them
+ [5, 6] => 1
+ [6, 5] => 1
+ [5, 4] => 1
+ [4, 5] => 1
+
+ All tie, return the one with the lowest index: 0
+
+=end comment
+################################################################################
+
+#--------------------------------------#
+# Copyright © 2025 PerlMonk Athanasius #
+#--------------------------------------#
+
+#===============================================================================
+=begin comment
+
+Assumption
+----------
+The x and y coordinates of the points in the given input list are all integers.
+
+Interface
+---------
+1. If no command-line arguments are given, the test suite is run. Otherwise:
+2. The x and y coordinates of the current location are entered on the command-
+ line, followed by a list of points. Each point is given as an x coordinate
+ followed by a y coordinate. All coordinates are integers.
+3. If the x-coordinate of the current location is negative, it must be preceded
+ by "--" to indicate that it is not a command-line flag.
+
+=end comment
+#===============================================================================
+
+use Test;
+
+subset Point of List where (Int, Int);
+
+#-------------------------------------------------------------------------------
+BEGIN
+#-------------------------------------------------------------------------------
+{
+ "\nChallenge 334, Task #2: Nearest Valid Point (Raku)\n".put;
+}
+
+#===============================================================================
+multi sub MAIN
+(
+ Int:D $x, #= The x-coordinate of the current location
+ Int:D $y, #= The y-coordinate of the current location
+
+ #| An even-sized list of point coordinates in x y order
+ *@points where { .all ~~ Int:D && .elems %% 2 }
+)
+#===============================================================================
+{
+ my Point @points_ = @points.rotor: 2;
+
+ "Input: \$x = $x, \$y = $y, \@points = (%s)\n".printf:
+ @points_.map( { '[' ~ @$_.join( ', ' ) ~ ']' } ).join: ', ';
+
+ my Int $index = nearest-valid-point( [ $x, $y ], @points_ );
+
+ "Output: $index".put;
+}
+
+#===============================================================================
+multi sub MAIN() # No input: run the test suite
+#===============================================================================
+{
+ run-tests();
+}
+
+#-------------------------------------------------------------------------------
+sub nearest-valid-point( Point:D $current, List:D[Point:D] $points --> Int:D )
+#-------------------------------------------------------------------------------
+{
+ my Int $index = -1;
+ my UInt $min-dist;
+
+ for 0 .. $points.end -> UInt $i
+ {
+ my Point $point = $points[ $i ];
+ my UInt $manhattan-dist;
+
+ if $point[ 0 ] == $current[ 0 ]
+ {
+ $manhattan-dist = ($point[ 1 ] - $current[ 1 ]).abs;
+ }
+ elsif $point[ 1 ] == $current[ 1 ]
+ {
+ $manhattan-dist = ($point[ 0 ] - $current[ 0 ]).abs;
+ }
+
+ if $manhattan-dist.defined &&
+ (!$min-dist.defined || $min-dist > $manhattan-dist)
+ {
+ $index = $i;
+ $min-dist = $manhattan-dist;
+ }
+ }
+
+ return $index;
+}
+
+#-------------------------------------------------------------------------------
+sub run-tests()
+#-------------------------------------------------------------------------------
+{
+ 'Running the test suite'.put;
+
+ for test-data.lines -> Str $line
+ {
+ my Str ($test-name, $x, $y, $points-str, $exp) = $line.split: / \| /;
+
+ for $test-name, $x, $y, $points-str, $exp
+ {
+ s/ ^ \s+ //;
+ s/ \s+ $ //;
+ }
+
+ my Point @points;
+
+ for $points-str.split: / \; /, :skip-empty
+ {
+ @points.push: [ .split( / \s+ /, :skip-empty ).map: { .Int } ];
+ }
+
+ my Point $current = [ $x.Int, $y.Int ];
+ my Int $index = nearest-valid-point( $current, @points );
+
+ is $index, $exp.Int, $test-name;
+ }
+
+ done-testing;
+}
+
+#-------------------------------------------------------------------------------
+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|3|4|1 2; 3 1; 2 4; 2 3| 2
+ Example 2|2|5|3 4; 2 3; 1 5; 2 5| 3
+ Example 3|1|1|2 2; 3 3; 4 4 |-1
+ Example 4|0|0|0 1; 1 0; 0 2; 2 0| 0
+ Example 5|5|5|5 6; 6 5; 5 4; 4 5| 0
+ END
+}
+
+################################################################################