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
/;