Perl Weekly Challenge 281.

My solutions (task 1 and task 2 ) to the The Weekly Challenge - 281.

Task 1: Check Color

Submitted by: Mohammad Sajid Anwar
You are given coordinates, a string that represents the coordinates of a
square of the chessboard as shown below:

[Chess board with black at bottom right. Coordinates go upward from 1 to 8
and leftward from a to h]

Write a script to return true if the square is light, and false if the square is dark.

Example 1
Input: $coordinates = "d3"
Output: true
Example 2
Input: $coordinates = "g5"
Output: false
Example 3
Input: $coordinates = "e6"
Output: true

I can convert all coordinates to the range 0-7. Then, black corresponds to squares whose coordinates add to an even number and white to odd. This yields a one-liner:

Examples:

perl -E '
for(@ARGV){/(.)(.)/;($x,$y)=(ord($1)-97,$2-1);say "$_ -> ", ($x+$y)%2?"True":"False"}
' d3 g5 e6

Results:

d3 -> True
g5 -> False
e6 -> True

The full code adds a few checks:

 1  # Perl weekly challenge 281
 2  # Task 1:  Check Color
 3  #
 4  # See https://wlmb.github.io/2024/08/04/PWC281/#task-1-check-color
 5  use v5.36;
 6  die <<~"FIN" unless @ARGV;
 7      Usage $0 P1 P2...
 8      to test whether position Pi in a chessboard corresponds to a white square,
 9      where Pi is of the form xy with x a letter in the range a-h and y a digit
10      in the range 1-8.
11      FIN
12  for(@ARGV){
13      warn("Bad format: $_"), next unless /^([a-hA-H])([1-7])$/;
14      my $x=ord(lc $1)-ord("a"); # convert to number 0-7
15      my $y=$2-1;
16      my $result=($x+$y)%2?"True":"False";
17      say "$_ -> $result";
18  }

Example:

./ch-1.pl d3 g5 e6

Task 2: Knight’s Move

Submitted by: Peter Campbell Smith
A Knight in chess can move from its current position to any square two rows or
columns plus one column or row away. So in the diagram below, if it starts a S,
it can move to any of the squares marked E.

Write a script which takes a starting position and an ending position and calculates
the least number of moves required.

Example 1
Input: $start = 'g2', $end = 'a8'
Ouput: 4

g2 -> e3 -> d5 -> c7 -> a8
Example 2
Input: $start = 'g2', $end = 'h2'
Ouput: 3

g2 -> e3 -> f1 -> h2

As the chessboard is finite and small, I straightforwardly construct all trajectories out of the starting position one step at a time until I reach the ending position. I use PDL to manage vector operations. I first build a table of allowed movements, the vectors obtained from [1,2] through arbitrary permutations and sign changes. I maintain a list of current positions, initialized to the starting position, and I repeatedly add all movements, discard repeated positions and discard positions that are out of range until I reach the ending position. In the short solution I allow visiting repeatedly the same position, though it is suboptimal. The result fits a 4-liner.

Example 1:

perl -MPDL -MPDL::NiceSlice -E '
($c,$e)=map{/(.)(.)/;pdl(ord($1)-97,$2-1)}@ARGV;$p=pdl[[1,2],[2,1]];$q=pdl[1,-1];
$m=pdl($p, $p*$q,-$p*$q,-$p)->clump(1,2);$i=0; while(($c!=$e)->orover->all){$n=
($c+$m(:,*))->clump(1,2);$c=$n->dice_axis(1,which(($n((0))>=0)&($n((0))<8)&($n((1))
>=0)&($n((1))<8)))->uniqvec;++$i;}say "@ARGV -> $i";
' g2 a8

Results:

g2 a8 -> 4

Example 2:

perl -MPDL -MPDL::NiceSlice -E '
($c,$e)=map{/(.)(.)/;pdl(ord($1)-97,$2-1)}@ARGV;$p=pdl[[1,2],[2,1]];$q=pdl[1,-1];
$m=pdl($p, $p*$q,-$p*$q,-$p)->clump(1,2);$i=0; while(($c!=$e)->orover->all){$n=
($c+$m(:,*))->clump(1,2);$c=$n->dice_axis(1,which(($n((0))>=0)&($n((0))<8)&($n((1))
>=0)&($n((1))<8)))->uniqvec;++$i;}say "@ARGV -> $i";
' g2 h2

Results:

g2 h2 -> 3

The full code adds some tests and avoids repetitions.

 1  # Perl weekly challenge 281
 2  # Task 2:  Knight’s Move
 3  #
 4  # See https://wlmb.github.io/2024/08/04/PWC281/#task-2-knight’s-move
 5  use v5.36;
 6  use PDL;
 7  use PDL::NiceSlice;
 8  use experimental qw(for_list);
 9  die <<~"FIN" unless @ARGV && @ARGV%2==0;
10      Usage: $0 S1 E1...
11      to find how many moves are required for a knight to go from position Si
12      to position Ei in a chessboard.
13      The positions are given in the format xy where x is a letter in the
14      range a-h and denotes the horizontal position while y is a digit between 1 and 8
15      and denotes vertical position.
16      FIN
17  my $moves=pdl[[1,2],[2,1]]; # Construct all moves of knight
18  my $signs=pdl[1,-1];
19  my $allmoves=pdl($moves, $moves*$signs, -$moves*$signs,-$moves)->clump(1,2);
20  for my($start, $end)(@ARGV){
21      my ($current, $goal)=map{ # convert to coordinate vectors, origin at (0,0)
22          warn("Bad format: $_"), next unless /^([a-hA-H])([1-8])$/;
23          pdl(ord(lc $1)-ord("a"), $2-1)
24      } ($start, $end);
25      my $iteration=0;
26      my $visited=zeroes(8,8);
27      $visited->indexND($current).=1;
28      until(($current==$goal)->andover->any){ # until we reach the goal
29          my $next=($current+$allmoves->dummy(1))->clump(1,2); # jump to new positions
30          $current=$next
31              ->dice_axis(  # remove invalid positions
32                   1, which(($next((0))>=0)&($next((0))<8)&($next((1))>=0)&($next((1))<8)))
33              ->uniqvec;     # remove duplicates
34          $current=$current->dice_axis( # remove previously visited
35                       1, which(!$visited->indexND($current))
36              );
37          $visited->indexND($current).=1;
38          ++$iteration;
39      }
40      say "From $start to $end -> $iteration movements";
41  }
42  

Example:

./ch-2.pl g2 a8 g2 h2

Results:

From g2 to a8 -> 4 movements
From g2 to h2 -> 3 movements

/;

Written on August 4, 2024