Perl Weekly Challenge 335.
My solutions (task 1 and task 2 ) to the The Weekly Challenge - 335.
Task 1: Common Characters
Submitted by: Mohammad Sajid Anwar
You are given an array of words.
Write a script to return all characters that is in every word in the given array
including duplicates.
Example 1
Input: @words = ("bella", "label", "roller")
Output: ("e", "l", "l")
Example 2
Input: @words = ("cool", "lock", "cook")
Output: ("c", "o")
Example 3
Input: @words = ("hello", "world", "pole")
Output: ("l", "o")
Example 4
Input: @words = ("abc", "def", "ghi")
Output: ()
Example 5
Input: @words = ("aab", "aac", "aaa")
Output: ("a", "a")
I count the appearances of each letter of each word, find the minimum over all words and repeat it the corresponding number of times in the output. This yields a two-liner.
Example 1:
perl -MList::Util=min -E '
for(@ARGV){my%l;$l{$_}++ for split "", $_;push @w, { %l}}%l=%{$w[0]};for $v
(keys%l){$l{$v}=min map{$_->{$v}}@w}say "@ARGV -> ", map{"$_ " x %l{$_}}keys %l;
' bella label roller
Results:
bella label roller -> e l l
Example 2:
perl -MList::Util=min -E '
for(@ARGV){my%l;$l{$_}++ for split "", $_;push @w, { %l}}%l=%{$w[0]};for $v
(keys%l){$l{$v}=min map{$_->{$v}}@w}say map{"$_ " x %l{$_}}keys %l;
' cool lock cook
Results:
o c
Example 3
perl -MList::Util=min -E '
for(@ARGV){my%l;$l{$_}++ for split "", $_;push @w, { %l}}%l=%{$w[0]};for $v
(keys%l){$l{$v}=min map{$_->{$v}}@w}say "@ARGV -> ", map{"$_ " x %l{$_}}keys %l;
' hello world pole
Results:
l o
Example 4
perl -MList::Util=min -E '
for(@ARGV){my%l;$l{$_}++ for split "", $_;push @w, { %l}}%l=%{$w[0]};for $v
(keys%l){$l{$v}=min map{$_->{$v}}@w}say "@ARGV -> ", map{"$_ " x %l{$_}}keys %l;
' abc def ghi
Results:
abc def ghi ->
Example 5
perl -MList::Util=min -E '
for(@ARGV){my%l;$l{$_}++ for split "", $_;push @w, { %l}}%l=%{$w[0]};for $v
(keys%l){$l{$v}=min map{$_->{$v}}@w}say "@ARGV -> ", map{"$_ " x %l{$_}}keys %l;
' aab aac aaa
Results:
aab aac aaa -> a a
Output: (“a”, “a”)
The full code is
1 # Perl weekly challenge 335
2 # Task 1: Common Characters
3 #
4 # See https://wlmb.github.io/2025/08/18/PWC335/#task-1-common-characters
5 use v5.36;
6 use List::Util qw(min);
7 die <<~"FIN" unless @ARGV;
8 Usage: $0 W1 W2...
9 to show characters common to all words W1 W2...
10 FIN
11 my @words;
12 for(@ARGV){ # count letters in each word
13 my %letters;
14 $letters{$_}++ for split "", $_;
15 push @words, { %letters}
16 }
17 my %result=%{$words[0]}; # check letters in first word
18 for my $letter(keys %result){
19 $result{$letter}=min map{$_->{$letter}//0} @words
20 }
21 say "@ARGV -> ", map {"$_ " x $result{$_}}
22 sort {$a cmp $b} keys %result;
Examples:
./ch-1.pl bella label roller
./ch-1.pl cool lock cook
./ch-1.pl hello world pole
./ch-1.pl abc def ghi
./ch-1.pl aab aac aaa
Results:
bella label roller -> e l l
cool lock cook -> c o
hello world pole -> l o
abc def ghi ->
aab aac aaa -> a a
Task 2: Find Winner
Submitted by: Mohammad Sajid Anwar
You are given an array of all moves by the two players.
Write a script to find the winner of the TicTacToe game if found based
on the moves provided in the given array.
UPDATE: Order move is in the order - A, B, A, B, A, ….
Example 1
Input: @moves = ([0,0],[2,0],[1,1],[2,1],[2,2])
Output: A
Game Board:
[ A _ _ ]
[ B A B ]
[ _ _ A ]
Example 2
Input: @moves = ([0,0],[1,1],[0,1],[0,2],[1,0],[2,0])
Output: B
Game Board:
[ A A B ]
[ A B _ ]
[ B _ _ ]
Example 3
Input: @moves = ([0,0],[1,1],[2,0],[1,0],[1,2],[2,1],[0,1],[0,2],[2,2])
Output: Draw
Game Board:
[ A A B ]
[ B B A ]
[ A B A ]
Example 4
Input: @moves = ([0,0],[1,1])
Output: Pending
Game Board:
[ A _ _ ]
[ _ B _ ]
[ _ _ _ ]
Example 5
Input: @moves = ([1,1],[0,0],[2,2],[0,1],[1,0],[0,2])
Output: B
Game Board:
[ B B B ]
[ A A _ ]
[ _ _ A ]
As the game ends at the moment there is a winner, I only have
to check the last move. It is a winning move if it lies on a straight
line with any two previous moves by the same player. I use PDL to
perform vector operations. The player P
that plays the last move
wins if the determinant of V
and W
is zero, where V=some move by
P-last move
and W=another move by P-last move
. If the last player
doesn’t win and all nine moves have been played, there is a draw. If
not, the result is pending
. If no player has finished three moves, the
result is pending
. The code may be squeezed into a three-liner. I
explain it in more detail in the full code below.
Examples:
perl -MPDL -MPDL::NiceSlice -E '
@j=qw(A B);for(@ARGV){$m=pdl($_);$p=1-($n=$m->dim(1))%2;$r="P", next if$n<5;$r=$j[$p],next
if w($m(:,$p:-2:2)-$m(:,-1));$r="D", next if $m->dim(1)==9;$r="P";}continue{say "$_ -> $r";}
sub w($m){$n=$m->dim(1);return(($m((0))*$m((1),*)-$m((1))*$m((0),*))==0)->sum>$n;}
' "[[0 0][2 0][1 1][2 1][2 2]]" "[[0 0][1 1][0 1][0 2][1 0][2 0]]" \
"[[0 0][1 1][2 0][1 0][1 2][2 1][0 1][0 2][2 2]]" "[[0 0][1 1]]" \
"[[1 1][0 0][2 2][0 1][1 0][0 2]]"
Results:
[[0 0][2 0][1 1][2 1][2 2]] -> A
[[0 0][1 1][0 1][0 2][1 0][2 0]] -> B
[[0 0][1 1][2 0][1 0][1 2][2 1][0 1][0 2][2 2]] -> D
[[0 0][1 1]] -> P
[[1 1][0 0][2 2][0 1][1 0][0 2]] -> B
Note that I compute the determinant of all pairs of previous relative moves. This yields trivial zeroes when I use the same move twice. Any other zero means a win.
The corresponding full code is:
1 # Perl weekly challenge 335
2 # Task 2: Find Winner
3 #
4 # See https://wlmb.github.io/2025/08/18/PWC335/#task-2-find-winner
5 use v5.36;
6 use feature qw(try);
7 use PDL;
8 die <<~"FIN" unless @ARGV;
9 Usage: $0 G1 G2...
10 to find the winner in the tic tac toe game Gi.
11 Each game is a string with the format
12 "[[X0 Y0][X1 Y1]...]"
13 where Xi Yi are the coordinates of the ith move, in the range 0..2.
14 Even numbered moves correspond to player A and odd to player B.
15 FIN
16 my @players=map {"Player $_"} qw(A B);
17 my $result;
18 for(@ARGV){
19 try {
20 my $moves=pdl($_);
21 die "Wrong shape. Expected array of 2D vectors: $_"
22 unless $moves->dim(0)==2; # each move should be 2D vector
23 die "Wrong move. Expected 0<=coordinate<=2: $_"
24 unless 0 <= $moves->min && $moves->max <= 2;
25 die "Repeated moves are invalid: $_"
26 unless $moves->uniqvec->dim(1)==$moves->dim(1);
27 my $length=$moves->dim(1); # length of game
28 my $last=1-$length%2; # last player
29 $result = "Pending", next if $length < 5; # game was too short
30 $result = $players[$last], next if
31 win(
32 $moves->slice(":,$last:-2:2") # previous moves of last player
33 -$moves->slice(":,-1") # with respect to last move
34 );
35 $result = "Draw", next
36 if $moves->dim(1)==9; # finished game without a winner
37 $result= "Pending"; # unfinished game
38 } catch($e) {
39 say $e;
40 undef $result;
41 }
42 } continue{
43 say "$_ -> $result" if defined $result;
44 }
45 sub win($relative){ # moves by one player relative to last
46 my $length=$relative->dim(1);
47 return (($relative->slice("(0)")*$relative->slice("(1),*")
48 - $relative->slice("(1)")*$relative->slice("(0),*")) # compute determinants
49 ==0)->sum # count zeroes
50 > $length; # win if larger than the trivial number
51 }
Example:
./ch-2.pl "[[0 0][2 0][1 1][2 1][2 2]]" "[[0 0][1 1][0 1][0 2][1 0][2 0]]" \
"[[0 0][1 1][2 0][1 0][1 2][2 1][0 1][0 2][2 2]]" "[[0 0][1 1]]" \
"[[1 1][0 0][2 2][0 1][1 0][0 2]]"
Results:
[[0 0][2 0][1 1][2 1][2 2]] -> Player A
[[0 0][1 1][0 1][0 2][1 0][2 0]] -> Player B
[[0 0][1 1][2 0][1 0][1 2][2 1][0 1][0 2][2 2]] -> Draw
[[0 0][1 1]] -> Pending
[[1 1][0 0][2 2][0 1][1 0][0 2]] -> Player B
/;