diff options
| author | Mohammad Sajid Anwar <Mohammad.Anwar@yahoo.com> | 2024-08-10 19:08:23 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-08-10 19:08:23 +0100 |
| commit | 4cae80b38ea97bc3c965f3a5b13fa04f2d550420 (patch) | |
| tree | 854287a3846bc428911aaaa9089416af1b6817d9 | |
| parent | 6a316155e8913f95236a0ef63f0fede7aceb2094 (diff) | |
| parent | 0ff774cf6f1e41d1928a2e1f022de5af8a9969a7 (diff) | |
| download | perlweeklychallenge-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-x | challenge-281/robbie-hatley/perl/ch-1.pl | 30 | ||||
| -rwxr-xr-x | challenge-281/robbie-hatley/perl/ch-2.pl | 188 |
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"; } |
