diff options
| author | Mohammad Sajid Anwar <Mohammad.Anwar@yahoo.com> | 2025-08-22 17:47:12 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-08-22 17:47:12 +0100 |
| commit | d4fc390f8276fa3a7d491ae6c025b977baceda0b (patch) | |
| tree | a18ede3eda3e60344fef259e5fe630062e81d9a1 | |
| parent | ec6cd1c30040e2337fd679057608aba79aa17427 (diff) | |
| parent | 1e81a243d59ff18b33c59b25d8ceee0dc781a1b5 (diff) | |
| download | perlweeklychallenge-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.txt | 1 | ||||
| -rwxr-xr-x | challenge-335/jo-37/perl/ch-1.pl | 106 | ||||
| -rwxr-xr-x | challenge-335/jo-37/perl/ch-2.pl | 127 |
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; +} |
