aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohammad Sajid Anwar <Mohammad.Anwar@yahoo.com>2024-08-10 19:08:23 +0100
committerGitHub <noreply@github.com>2024-08-10 19:08:23 +0100
commit4cae80b38ea97bc3c965f3a5b13fa04f2d550420 (patch)
tree854287a3846bc428911aaaa9089416af1b6817d9
parent6a316155e8913f95236a0ef63f0fede7aceb2094 (diff)
parent0ff774cf6f1e41d1928a2e1f022de5af8a9969a7 (diff)
downloadperlweeklychallenge-club-4cae80b38ea97bc3c965f3a5b13fa04f2d550420.tar.gz
perlweeklychallenge-club-4cae80b38ea97bc3c965f3a5b13fa04f2d550420.tar.bz2
perlweeklychallenge-club-4cae80b38ea97bc3c965f3a5b13fa04f2d550420.zip
Merge pull request #10573 from robbie-hatley/rh281
Made major improvements to my solutions for both tasks of PWCC 281.
-rwxr-xr-xchallenge-281/robbie-hatley/perl/ch-1.pl30
-rwxr-xr-xchallenge-281/robbie-hatley/perl/ch-2.pl188
2 files changed, 75 insertions, 143 deletions
diff --git a/challenge-281/robbie-hatley/perl/ch-1.pl b/challenge-281/robbie-hatley/perl/ch-1.pl
index 07908c1c16..577606e0af 100755
--- a/challenge-281/robbie-hatley/perl/ch-1.pl
+++ b/challenge-281/robbie-hatley/perl/ch-1.pl
@@ -13,7 +13,7 @@ Task 281-1: Check Color
Submitted by: Mohammad S Anwar
Write a script which, given the coordinates of a square on a
chessboard in algebraic notation, prints "true" if the square
-is white, "false" if the square is black.
+is white or "false" if the square is black.
Example 1: Input: 'd3' Output: 'true'
Example 2: Input: 'g5' Output: 'false'
Example 3: Input: 'e6' Output: 'true'
@@ -38,22 +38,30 @@ Output is to STDOUT and will be each input followed by the corresponding output.
# ------------------------------------------------------------------------------------------------------------
# PRAGMAS, MODULES, AND SUBS:
-use v5.36;
-sub parity ($x) {
- return 'error' if $x !~ m/^[a-h][1-8]$/;
- ((ord(substr($x,0,1))-97)+(ord(substr($x,1,1))-49))%2
-}
+ # Use Perl version "v5.36" or higher so we can use "signatures":
+ use v5.36;
+
+ # Is a given algebraic notation valid?
+ sub valid_alg ($x) {$x =~ m/^[a-h][1-8]$/}
+
+ # Convert algebraic notation to 0-indexed coordinate:
+ sub alg_to_coord ($x) {return [ord(substr($x,0,1))-97,ord(substr($x,1,1))-49]}
+
+ # Return parity of hops from a1 to given square:
+ sub parity ($a) {my $c=alg_to_coord($a);($c->[0]+$c->[1])%2}
# ------------------------------------------------------------------------------------------------------------
# INPUTS:
-my @coords = @ARGV ? eval($ARGV[0]) : ('d3', 'g5', 'e6');
+my @squares = @ARGV ? eval($ARGV[0]) : ('d3', 'g5', 'e6');
+# Expected outputs: true false true
# ------------------------------------------------------------------------------------------------------------
# MAIN BODY OF PROGRAM:
-say 'Coord Parity Color Result ';
-for my $coord (@coords) {
- my $parity = parity($coord);
+say 'Square Parity Color Result ';
+for my $square (@squares) {
+ if (!valid_alg($square)) {say "Error: \"$square\" is not a valid algebraic chess location.";next}
+ my $parity = parity($square);
my $color = $parity ? 'white' : 'black';
my $result = $parity ? 'true' : 'false';
- printf("%-8s%-8s%-8s%-8s\n", $coord, $parity, $color, $result);
+ printf(" %-6s %-6s%-8s%-8s\n", $square, $parity, $color, $result);
}
diff --git a/challenge-281/robbie-hatley/perl/ch-2.pl b/challenge-281/robbie-hatley/perl/ch-2.pl
index bc60492c3b..b80349f04a 100755
--- a/challenge-281/robbie-hatley/perl/ch-2.pl
+++ b/challenge-281/robbie-hatley/perl/ch-2.pl
@@ -28,21 +28,17 @@ Path: g2 -> e3 -> f1 -> h2
--------------------------------------------------------------------------------------------------------------
PROBLEM NOTES:
I suppose I could use recursion for this and use recursion depth as "hops" counter, but that would involve
-accessing global variables from within functions (which seems nasty) and deep stacks (which I don't like).
+accessing global variables from within functions (which seems nasty) and a deep stack (which I don't like).
So I'll use a variant of Breadth-First Search. I'll make a hash "%Squares" of all 64 squares, with their keys
being their algebraic notations and their values being [visited, hops] all initialized to [0,inf] except for
-start which is [0,0]. I'll make a variable $current to keep track of "current hops from start" and initialize
-it to $start. I'll then process the itinerary for so long as its not empty by doing the following:
- 1. Shift each square in the itinerary from the left into variable "$next".
- 2. Set "hops" for next to min(existing, current+1).
- 3. Set current = next.
- 4. Set current as "visited".
- 5. Get "octopus" of squares which can be visited next.
- 6. For each "arm", set its hops to min(existing, 1+current).
- 7. Push each unvisited arm onto right of itinerary.
+start which is [0,0]. I'll make a variable "$current" to keep track of "current hops from start". I'll then
+process the itinerary for so long as its not empty by doing the following:
+ 1. Shift left-most "@itinerary" square into "$current".
+ 2. Set current as "visited".
+ 3. Get octopus of squares which can be visited next.
+ 4. For each unvisited arm of octopus, set hops current+1 and push onto right end of "@itinerary".
After the queue empties, $squares{$end}->[1] should contain "minimum hops to get from start to end".
-
--------------------------------------------------------------------------------------------------------------
IO NOTES:
Input is via either built-in variables or via @ARGV. If using @ARGV, provide one argument which must be a
@@ -56,175 +52,103 @@ Output is to STDOUT and will be each input followed by the corresponding output.
# ------------------------------------------------------------------------------------------------------------
# PRAGMAS, MODULES, AND SUBS:
-# Insist on using Perl version "v5.40" or higher in order to get "inf":
-use v5.40;
-
-# Allow experimental "inf", "nan":
-use experimental 'builtin';
-
-# Use the "min" function from "List::Util":
-use List::Util 'min';
-
-# Do we want to debug?
-my $db = 0;
+# Use Perl version "v5.36" or higher so we can use "signatures":
+use v5.36;
# Is a given algebraic notation valid?
sub valid_alg ($x) {$x =~ m/^[a-h][1-8]$/}
-# Is a given 0-indexed coordinates valid?
-sub valid_coords ($x) {$x->[0] >= 0 && $x->[0] <= 7 && $x->[1] >= 0 && $x->[1] <= 7}
-
-# Convert algebraic notation to 0-indexed coordinates:
-sub alg_to_coords ($x) {
- # Return "error" is $alg isn't valid algebraic notation:
- return 'error' if !valid_alg($x);
-
- # Convert algebraic notation to 0-indexed coordinates and return to sender:
- return [ord(substr($x,0,1))-97,ord(substr($x,1,1))-49];
-}
+# Is a given 0-indexed coordinate valid?
+sub valid_coord ($x) {$x->[0] >= 0 && $x->[0] <= 7 && $x->[1] >= 0 && $x->[1] <= 7}
-# Convert algebraic notation to 0-indexed coordinates:
-sub coords_to_alg ($x) {
- # Return "error" is $x aren't valid:
- return 'error' if !valid_coords($x);
+# Convert algebraic notation to 0-indexed coordinate:
+sub alg_to_coord ($x) {return [ord(substr($x,0,1))-97,ord(substr($x,1,1))-49]}
- # Convert 0-indexed coordinates to algebraic notation and return to sender:
- return chr($x->[0]+97).chr($x->[1]+49);
-}
+# Convert 0-indexed coordinate to algebraic notation:
+sub coord_to_alg ($x) {return chr($x->[0]+97).chr($x->[1]+49)}
# The moves a chess knight can make are an 8-armed octopus:
sub octopus ($x) {
- # Return "error" is $x isn't valid algebraic notation:
- return 'error' if $x !~ m/^[a-h][1-8]$/;
-
- # Convert algebraic notation to 0-indexed coordinates:
- my $coords = alg_to_coords($x);
+ # Convert algebraic notation to 0-indexed coordinate:
+ my $coord = alg_to_coord($x);
# Make an octopus:
my @octopus;
- # Add up to 8 arms to octopus:
- my $arm;
-
- # Arm 1:
- $arm = [$coords->[0]+1,$coords->[1]+2];
- if (valid_coords($arm)) {push @octopus, coords_to_alg($arm)}
-
- # Arm 2:
- $arm = [$coords->[0]+2,$coords->[1]+1];
- if (valid_coords($arm)) {push @octopus, coords_to_alg($arm)}
-
- # Arm 3:
- $arm = [$coords->[0]+2,$coords->[1]-1];
- if (valid_coords($arm)) {push @octopus, coords_to_alg($arm)}
-
- # Arm 4:
- $arm = [$coords->[0]+1,$coords->[1]-2];
- if (valid_coords($arm)) {push @octopus, coords_to_alg($arm)}
-
- # Arm 5:
- $arm = [$coords->[0]-1,$coords->[1]-2];
- if (valid_coords($arm)) {push @octopus, coords_to_alg($arm)}
-
- # Arm 6:
- $arm = [$coords->[0]-2,$coords->[1]-1];
- if (valid_coords($arm)) {push @octopus, coords_to_alg($arm)}
-
- # Arm 7:
- $arm = [$coords->[0]-2,$coords->[1]+1];
- if (valid_coords($arm)) {push @octopus, coords_to_alg($arm)}
-
- # Arm 8:
- $arm = [$coords->[0]-1,$coords->[1]+2];
- if (valid_coords($arm)) {push @octopus, coords_to_alg($arm)}
+ # Add up to 8 tentacles to octopus:
+ my @hooks = ([+1,+2],[+2,+1],[-1,+2],[-2,+1],[-1,-2],[-2,-1],[+1,-2],[+2,-1]);
+ for my $hook (@hooks) {
+ my $tentacle = [$coord->[0]+$hook->[0],$coord->[1]+$hook->[1]];
+ if (valid_coord($tentacle)) {push @octopus, coord_to_alg($tentacle)}
+ }
- # Return this monster to caller:
+ # Return octopus to caller:
return @octopus;
}
+# What is the minimum number of hops for a chess knight to get from point A to point B?
sub min_hops ($start, $end) {
- # Abort if start or end points are not valid algebraic coordinates on a chess board:
- return 'error' if $start !~ m/^[a-h][1-8]$/;
- return 'error' if $end !~ m/^[a-h][1-8]$/;
-
# Make a hash of 64 squares with keys being algebraic coordinates and values being [visited,hops],
- # and initialize all values to [0,inf] meaning [not visited, indefinite distance away]:
+ # and initialize all values to {visited => 0, hops => undef}:
my %squares;
for my $x ('a'..'h') {
for my $y (1..8) {
- $squares{$x.$y}=[0,builtin::inf];
+ $squares{$x.$y} = {visited => 0, hops => undef};
}
}
- # Since "start" is 0 hops away from "start', set its hops 0:
- $squares{$start}->[1]=0;
+ # Because "$start" is our reference point for measuring hops, set its hops to 0:
+ $squares{$start}->{hops} = 0;
+
+ # Make an itinerary of squares to visit:
+ my @itinerary;
- # Make-and-initialize an itinerary of squares to visit, starting with the "start" square:
- my @itinerary = ($start);
+ # The first stop on our itinerary is our starting point:
+ push @itinerary, $start;
- # Make a "$current" variable to keep track of our current location and how many hops from "start" we are,
- # and initialize it to $start so that its "hops from start" starts at 0:
- my $current = $start;
+ # Make a "$current" variable to keep track of our current location:
+ my $current;
# Process itinerary while it's not empty:
while (@itinerary) {
- # Grab next location to visit by shifting it from left end of itinerary:
- my $next = shift @itinerary;
-
- # Sanity check: return "error" if $next is not valid algebraic notation:
- return 'error' if !valid_alg($next);
+ # Visit next location on itinerary by shifting it from left end to $current:
+ $current = shift @itinerary;
- # Set $next's hops to min(existing, 1+current):
- $squares{$next}->[1] = min($squares{$next}->[1], 1 + $squares{$current}->[1]);
+ # Mark "$current" as "visited":
+ $squares{$current}->{visited} = 1;
- # Visit $next by setting $current = $next and marking $current as "visited":
- $current = $next;
- $squares{$current}->[0]=1;
+ # Have we reached our destination? If so, stop traveling and return how many hops it took to get here:
+ if ($current eq $end) {return $squares{$current}->{hops}}
# Get a list of squares we can move to from here:
my @octopus = octopus($current);
- # For each arm of the octopus, set its "hops" to min(existing, 1+current),
- # to indicate that we COULD get to it from start in no-more-than that number of hops,
- # and if it hasn't been visited yet, push it onto itinerary:
+ # For each arm of the octopus, if it hasn't yet been visited, set its "hops" to current+1 and push it
+ # onto right end of itinerary:
for my $arm (@octopus) {
- # NOTE RH 2024-08-07: I've verified that this sub gives wrong (HIGH!) values without this next line:
- $squares{$arm}->[1] = min($squares{$arm}->[1], 1 + $squares{$current}->[1]);
- # Now that we've addressed the (VERY IMPORTANT) "squares we don't intend to visit again" above,
- # we can enqueue the squares we DO intend to visit:
- push @itinerary, $arm if 0 == $squares{$arm}->[0];
+ if (!$squares{$arm}->{visited}) {
+ $squares{$arm}->{hops} = $squares{$current}->{hops}+1;
+ push @itinerary, $arm;
+ }
}
}
- # Print grid if debugging:
- if ($db) {
- say '';
- say "$_ $squares{$_}->[0] $squares{$_}->[1]" for sort keys %squares;
- say '';
- }
-
- # Return the minimum number of hops to get from start to end:
- return $squares{$end}->[1]
+ # We can't possibly get here. But if we do, inform user that something bizarre has happened and die:
+ die "I have climbed highest mountains; I have trod through the fields;\n"
+ ."I have run, I have crawled, I have scaled these city walls, only to\n"
+ ."be with you; but I still haven't found what I'm looking for.\n";
}
# ------------------------------------------------------------------------------------------------------------
# INPUTS:
-my @arrays = @ARGV ? eval($ARGV[0]) :
-(
- # Example 1 input:
- ['g2', 'a8'],
- # Expected output: 4
-
- # Example 2 input:
- ['g2', 'h2'],
- # Expected output: 3
-);
+my @arrays = @ARGV ? eval($ARGV[0]) : (['g2', 'a8'],['g2', 'h2']);
+# Expected outputs: 4 3
# ------------------------------------------------------------------------------------------------------------
# MAIN BODY OF PROGRAM:
for my $aref (@arrays) {
- my $start = $aref->[0];
- my $end = $aref->[1];
+ my $start = $aref->[0]; if (!valid_alg($start)) {say 'Error: invalid start \"$start\"'; next}
+ my $end = $aref->[1]; if (!valid_alg($end )) {say 'Error: invalid end \"$end\"'; next}
my $hops = min_hops($start, $end);
say "Start: $start End: $end Hops : $hops";
}