aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohammad Sajid Anwar <Mohammad.Anwar@yahoo.com>2025-08-22 17:47:12 +0100
committerGitHub <noreply@github.com>2025-08-22 17:47:12 +0100
commitd4fc390f8276fa3a7d491ae6c025b977baceda0b (patch)
treea18ede3eda3e60344fef259e5fe630062e81d9a1
parentec6cd1c30040e2337fd679057608aba79aa17427 (diff)
parent1e81a243d59ff18b33c59b25d8ceee0dc781a1b5 (diff)
downloadperlweeklychallenge-club-d4fc390f8276fa3a7d491ae6c025b977baceda0b.tar.gz
perlweeklychallenge-club-d4fc390f8276fa3a7d491ae6c025b977baceda0b.tar.bz2
perlweeklychallenge-club-d4fc390f8276fa3a7d491ae6c025b977baceda0b.zip
Merge pull request #12553 from jo-37/contrib
Solutions to challenge 335
-rw-r--r--challenge-335/jo-37/blog.txt1
-rwxr-xr-xchallenge-335/jo-37/perl/ch-1.pl106
-rwxr-xr-xchallenge-335/jo-37/perl/ch-2.pl127
3 files changed, 234 insertions, 0 deletions
diff --git a/challenge-335/jo-37/blog.txt b/challenge-335/jo-37/blog.txt
new file mode 100644
index 0000000000..b6dae7b1cc
--- /dev/null
+++ b/challenge-335/jo-37/blog.txt
@@ -0,0 +1 @@
+https://github.sommrey.de/the-bears-den/2025/08/22/ch-335.html
diff --git a/challenge-335/jo-37/perl/ch-1.pl b/challenge-335/jo-37/perl/ch-1.pl
new file mode 100755
index 0000000000..9c519ffbc5
--- /dev/null
+++ b/challenge-335/jo-37/perl/ch-1.pl
@@ -0,0 +1,106 @@
+#!/usr/bin/perl
+
+use v5.26;
+use Test2::V0 -no_srand;
+use Test2::Tools::Subtest 'subtest_streamed';
+use Getopt::Long;
+use experimental 'signatures';
+
+use Set::Bag;
+use List::MoreUtils 'frequency';
+use List::Util qw(reduce pairmap);
+
+
+### Options and Arguments
+
+my ($tests, $examples, $verbose);
+GetOptions(
+ 'examples!' => \$examples,
+ 'tests!' => \$tests,
+ 'verbose!' => \$verbose,
+) or usage();
+
+run_tests($examples, $tests); # tests do not return
+
+usage() unless @ARGV;
+
+sub usage {
+ die <<~EOS;
+ $0 - common characters
+
+ usage: $0 [-examples] [-tests] [WORD...]
+
+ -examples
+ run the examples from the challenge
+
+ -tests
+ run some tests
+
+ WORD...
+ list of words
+
+ EOS
+}
+
+
+### Input and Output
+
+say "(@{[common_chars(@ARGV)]})";
+
+
+### Implementation
+#
+# For details see:
+# https://github.sommrey.de/the-bears-den/2025/08/22/ch-335.html#task-1
+
+
+sub common_chars {
+ pairmap {($a) x $b} (
+ reduce {$a & $b} map Set::Bag->new(frequency split //), @_
+ )->grab;
+}
+
+
+### Examples and Tests
+
+sub run_tests ($examples, $tests) {
+ return unless $examples || $tests;
+
+ state sub run_example ($args, $expected, $name) {
+ my @result = common_chars(@$args);
+ my $exp = Test2::Compare::Bag->new;
+ $exp->set_ending(1);
+ $exp->add_item($_) for @$expected;
+ like \@result, $exp,
+ "$name: (@$args) -> (@$expected)";
+ }
+
+ plan 2;
+
+ $examples ? subtest_streamed(examples => sub {
+ my @examples = (
+ [["bella", "label", "roller"], [qw(e l l)], 'example 1'],
+ [["cool", "lock", "cook"], [qw(c o)], 'example 2'],
+ [["hello", "world", "pole"], [qw(l o)], 'example 3'],
+ [["abc", "def", "ghi"], [], 'example 4'],
+ [["aab", "aac", "aaa"], [qw(a a)], 'example 5'],
+ );
+ plan scalar @examples;
+ for (@examples) {
+ run_example @$_;
+ }
+ }) : pass 'skip examples';
+
+ $tests ? subtest_streamed(tests => sub {
+ my @tests = (
+ [["aabc"], [qw(a a b c)], 'single word'],
+ [["höhle", "röhre"], [qw(e h ö)], 'umlauts'],
+ );
+ plan scalar @tests;
+ for (@tests) {
+ run_example @$_;
+ }
+ }) : pass 'skip tests';
+
+ exit;
+}
diff --git a/challenge-335/jo-37/perl/ch-2.pl b/challenge-335/jo-37/perl/ch-2.pl
new file mode 100755
index 0000000000..24892284e7
--- /dev/null
+++ b/challenge-335/jo-37/perl/ch-2.pl
@@ -0,0 +1,127 @@
+#!/usr/bin/perl
+
+use v5.26;
+use Test2::V0 qw(!float -no_srand);
+use Test2::Tools::Subtest 'subtest_streamed';
+use Getopt::Long;
+use experimental 'signatures';
+
+use PDL;
+use PDL::NiceSlice;
+
+
+### Options and Arguments
+
+my ($tests, $examples, $verbose);
+GetOptions(
+ 'examples!' => \$examples,
+ 'tests!' => \$tests,
+ 'verbose!' => \$verbose,
+) or usage();
+
+run_tests($examples, $tests); # tests do not return
+
+usage() unless @ARGV;
+
+sub usage {
+ die <<~EOS;
+ $0 - Tic Tac Toe
+
+ usage: $0 [-examples] [-tests] [-verbose] [MOVE...]
+
+ -examples
+ run the examples from the challenge
+
+ -tests
+ run some tests
+
+ -verbose
+ print filled board
+
+ MOVE...
+ list of moves in a form like '[x, y],...' or 'x,y;...'
+
+ EOS
+}
+
+
+### Input and Output
+
+say tictactoe("@ARGV");
+
+
+### Implementation
+#
+# For details see:
+# https://github.sommrey.de/the-bears-den/2025/08/22/ch-335.html#task-2
+
+use constant N => 3;
+use Constant::Generate {A => 1, B => N + 1}, dualvar => 1;
+
+{
+ my $lines;
+
+ BEGIN {
+ my $rows = ndcoords indx, N, N;
+ $lines = $rows->glue(2, $rows(-1:0)->sever,
+ $rows->diagonal(1, 2)->sever,
+ $rows(,-1:0)->diagonal(1, 2)->sever);
+ }
+
+ sub tictactoe {
+ my $moves = indx @_;
+ my $board = zeroes long, N, N;
+ $board->indexND($moves) .= long(A, B)->range(0, $moves->dim(1), 'p');
+ say $board if $verbose;
+ die "overwritten" if which($board)->nelem < $moves->dim(1);
+ my $winner = setops(
+ $board->indexND($lines)->sumover, 'AND', N * long(A, B)
+ ) / N;
+ die "post-final move" if $winner->nelem > 1;
+ return $board->all ? "Draw" : "Pending" if $winner->isempty;
+ $winner == A ? A : B; # return dual-valued constant
+ }
+}
+
+
+### Examples and Tests
+
+sub run_tests ($examples, $tests) {
+ return unless $examples || $tests;
+
+ state sub run_example ($args, $expected, $name) {
+ my $result = tictactoe(@$args);
+ is $result, $expected,
+ qq{$name: (@{[map "[@$_]", @$args]}) -> $expected};
+ }
+
+ plan 2;
+
+ $examples ? subtest_streamed(examples => sub {
+ my @examples = (
+ [[[0,0],[2,0],[1,1],[2,1],[2,2]], A, 'example 1'],
+ [[[0,0],[1,1],[0,1],[0,2],[1,0],[2,0]], B, 'example 2'],
+ [[[0,0],[1,1],[2,0],[1,0],[1,2],[2,1],[0,1],[0,2],[2,2]],
+ "Draw", 'example 3'],
+ [[[0,0],[1,1]], "Pending", 'example 4'],
+ [[[1,1],[0,0],[2,2],[0,1],[1,0],[0,2]], B, 'example 5'],
+ );
+ plan scalar @examples;
+ for (@examples) {
+ run_example @$_;
+ }
+ }) : pass 'skip examples';
+
+ $tests ? subtest_streamed(tests => sub {
+ plan 4;
+ like dies {tictactoe([1, 1], [1, 1])}, qr/overwritten/, 'overwritten';
+ like dies {tictactoe([1,1],[0,0],[2,2],[0,1],[1,0],[0,2],[1,2])},
+ qr/post-final/, 'post-final move';
+ like dies {tictactoe([0, 0], [0, N])}, qr/out-of-bounds/,
+ 'out of bounds';
+ is tictactoe([0,1],[1,1],[1,0],[1,2],[2,0],[2,1],[0,2],[2,2],[0,0]),
+ A, 'double win';
+ }) : pass 'skip tests';
+
+ exit;
+}