aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xchallenge-337/e-choroba/perl/ch-1.pl36
-rwxr-xr-xchallenge-337/e-choroba/perl/ch-2.pl23
-rw-r--r--challenge-339/conor-hoekstra/ch-1.bqn28
-rw-r--r--challenge-339/conor-hoekstra/ch-2.bqn13
-rw-r--r--challenge-340/ash/raku/ch-1.raku13
-rw-r--r--challenge-340/ash/raku/ch-2.raku12
-rw-r--r--challenge-340/bob-lied/README.md8
-rw-r--r--challenge-340/bob-lied/perl/ch-1.pl60
-rw-r--r--challenge-340/bob-lied/perl/ch-2.pl137
-rw-r--r--challenge-340/conor-hoekstra/ch-1.bqn14
-rw-r--r--challenge-340/conor-hoekstra/ch-2.bqn15
-rwxr-xr-xchallenge-340/e-choroba/perl/ch-1.pl20
-rwxr-xr-xchallenge-340/e-choroba/perl/ch-2.pl34
-rwxr-xr-xchallenge-340/feng-chang/raku/ch-1.raku6
-rwxr-xr-xchallenge-340/feng-chang/raku/ch-2.raku5
-rwxr-xr-xchallenge-340/feng-chang/raku/test.raku28
-rw-r--r--challenge-340/lubos-kolouch/perl/ch-1.pl52
-rw-r--r--challenge-340/lubos-kolouch/perl/ch-2.pl64
-rw-r--r--challenge-340/lubos-kolouch/python/ch-1.py53
-rw-r--r--challenge-340/lubos-kolouch/python/ch-2.py54
-rw-r--r--challenge-340/mahnkong/perl/ch-1.pl19
-rw-r--r--challenge-340/mahnkong/perl/ch-2.pl23
-rw-r--r--challenge-340/mark-anderson/raku/ch-1.raku20
-rw-r--r--challenge-340/mark-anderson/raku/ch-2.raku13
-rwxr-xr-xchallenge-340/perlboy1967/perl/ch1.pl36
-rwxr-xr-xchallenge-340/perlboy1967/perl/ch2.pl43
-rw-r--r--challenge-340/peter-campbell-smith/blog.txt1
-rwxr-xr-xchallenge-340/peter-campbell-smith/perl/ch-1.pl49
-rwxr-xr-xchallenge-340/peter-campbell-smith/perl/ch-2.pl41
-rw-r--r--challenge-340/pokgopun/go/ch-1.go118
-rw-r--r--challenge-340/pokgopun/go/ch-2.go90
-rw-r--r--challenge-340/pokgopun/python/ch-1.py90
-rw-r--r--challenge-340/pokgopun/python/ch-2.py79
-rw-r--r--challenge-340/richard-park/apl/AscendingNumbers.aplf15
-rw-r--r--challenge-340/richard-park/apl/DuplicateRemovals.aplf15
-rwxr-xr-xchallenge-340/simon-proctor/raku/ch-1.raku25
-rwxr-xr-xchallenge-340/simon-proctor/raku/ch-2.raku20
-rw-r--r--challenge-340/wlmb/blog.txt1
-rwxr-xr-xchallenge-340/wlmb/perl/ch-1.pl15
-rwxr-xr-xchallenge-340/wlmb/perl/ch-2.pl13
-rw-r--r--challenge-340/zapwai/perl/ch-1.pl39
-rw-r--r--challenge-340/zapwai/perl/ch-2.pl26
42 files changed, 1462 insertions, 4 deletions
diff --git a/challenge-337/e-choroba/perl/ch-1.pl b/challenge-337/e-choroba/perl/ch-1.pl
new file mode 100755
index 0000000000..5db9dfe323
--- /dev/null
+++ b/challenge-337/e-choroba/perl/ch-1.pl
@@ -0,0 +1,36 @@
+#!/usr/bin/perl
+use warnings;
+use strict;
+use experimental qw( signatures );
+
+sub smaller_than_current(@num1) {
+ map { my $x = $_; scalar grep $_ < $x, @num1 } @num1
+}
+
+# Useful for large arrays with some values repeated.
+sub smaller_than_current_fast(@num1) {
+ my %cache;
+ map { my $x = $_; $cache{$_} //= scalar grep $_ < $x, @num1 } @num1
+}
+
+use Test2::V0;
+plan(2 * 5 + 1);
+
+for my $smaller_than_current (\&smaller_than_current,
+ \&smaller_than_current_fast
+) {
+ is [$smaller_than_current->(6, 5, 4, 8)], [2, 1, 0, 3], 'Example 1';
+ is [$smaller_than_current->(7, 7, 7, 7)], [0, 0, 0, 0], 'Example 2';
+ is [$smaller_than_current->(5, 4, 3, 2, 1)], [4, 3, 2, 1, 0], 'Example 3';
+ is [$smaller_than_current->(-1, 0, 3, -2, 1)], [1, 2, 4, 0, 3], 'Example 4';
+ is [$smaller_than_current->(0, 1, 1, 2, 0)], [0, 2, 2, 4, 0], 'Example 5';
+}
+
+my @long = map int rand 1000, 1 .. 1_000;
+is smaller_than_current(@long), smaller_than_current_fast(@long), 'same';
+
+use Benchmark qw{ cmpthese };
+cmpthese(-3, {
+ naive => sub { smaller_than_current(@long) },
+ optimized => sub { smaller_than_current_fast(@long) },
+});
diff --git a/challenge-337/e-choroba/perl/ch-2.pl b/challenge-337/e-choroba/perl/ch-2.pl
new file mode 100755
index 0000000000..268fb7db52
--- /dev/null
+++ b/challenge-337/e-choroba/perl/ch-2.pl
@@ -0,0 +1,23 @@
+#!/usr/bin/perl
+use warnings;
+use strict;
+use experimental qw( signatures );
+
+use PDL;
+
+sub odd_matrix($row, $col, @locations) {
+ my $m = zeroes($col, $row);
+ for my $location (@locations) {
+ $m->slice($location->[1]) += 1;
+ $m->slice("", $location->[0]) += 1;
+ }
+ return ($m % 2)->sum
+}
+
+use Test::More tests => 5;
+
+is odd_matrix(2, 3, [0, 1], [1, 1]), 6, 'Example 1';
+is odd_matrix(2, 2, [1, 1], [0, 0]), 0, 'Example 2';
+is odd_matrix(3, 3, [0, 0], [1, 2], [2, 1]), 0, 'Example 3';
+is odd_matrix(1, 5, [0, 2], [0, 4]), 2, 'Example 4';
+is odd_matrix(4, 2, [1, 0], [3, 1], [2, 0], [0, 1]), 8, 'Example 5';
diff --git a/challenge-339/conor-hoekstra/ch-1.bqn b/challenge-339/conor-hoekstra/ch-1.bqn
new file mode 100644
index 0000000000..a54b321e16
--- /dev/null
+++ b/challenge-339/conor-hoekstra/ch-1.bqn
@@ -0,0 +1,28 @@
+# For up to date code:
+# https://github.com/codereport/bqn-code/blob/main/pwc/339-1.bqn
+
+u ⇐ •Import "/home/cph/bqn-test/test.bqn"
+fn ⇐ •Import "/home/cph/bqn-code/lib/fun.bqn"
+
+MaxProductDiff ← { ⌈´{ 𝕊a‿b‿c‿d: (a×b)-c×d }¨4 fn.ChooseWR 𝕩 } # solution 1
+MaxProductDiff2 ← { ⌈´{ -´×˝2‿2⥊𝕩 }¨4 fn.ChooseWR 𝕩 } # solution 2 (explicit)
+MaxProductDiff3 ← ⌈´·(-´·×˝2‿2⊸⥊)¨4⊸fn.ChooseWR # solution 3 (tacit)
+
+# Tests
+u.UnitTest (MaxProductDiff ⟨5, 9, 3, 4, 6⟩) ≡ 42
+u.UnitTest (MaxProductDiff ⟨1, ¯2, 3, ¯4⟩) ≡ 10
+u.UnitTest (MaxProductDiff ⟨¯3, ¯1, ¯2, ¯4⟩) ≡ 10
+u.UnitTest (MaxProductDiff ⟨10, 2, 0, 5, 1⟩) ≡ 50
+u.UnitTest (MaxProductDiff ⟨7, 8, 9, 10, 10⟩) ≡ 44
+
+u.UnitTest (MaxProductDiff2 ⟨5, 9, 3, 4, 6⟩) ≡ 42
+u.UnitTest (MaxProductDiff2 ⟨1, ¯2, 3, ¯4⟩) ≡ 10
+u.UnitTest (MaxProductDiff2 ⟨¯3, ¯1, ¯2, ¯4⟩) ≡ 10
+u.UnitTest (MaxProductDiff2 ⟨10, 2, 0, 5, 1⟩) ≡ 50
+u.UnitTest (MaxProductDiff2 ⟨7, 8, 9, 10, 10⟩) ≡ 44
+
+u.UnitTest (MaxProductDiff3 ⟨5, 9, 3, 4, 6⟩) ≡ 42
+u.UnitTest (MaxProductDiff3 ⟨1, ¯2, 3, ¯4⟩) ≡ 10
+u.UnitTest (MaxProductDiff3 ⟨¯3, ¯1, ¯2, ¯4⟩) ≡ 10
+u.UnitTest (MaxProductDiff3 ⟨10, 2, 0, 5, 1⟩) ≡ 50
+u.UnitTest (MaxProductDiff3 ⟨7, 8, 9, 10, 10⟩) ≡ 44
diff --git a/challenge-339/conor-hoekstra/ch-2.bqn b/challenge-339/conor-hoekstra/ch-2.bqn
new file mode 100644
index 0000000000..367b144c92
--- /dev/null
+++ b/challenge-339/conor-hoekstra/ch-2.bqn
@@ -0,0 +1,13 @@
+# For up to date code:
+# https://github.com/codereport/bqn-code/blob/main/pwc/339-2.bqn
+
+u ⇐ •Import "/home/cph/bqn-test/test.bqn"
+
+PeakPoint ← 0⌈´+`
+
+# Tests
+u.UnitTest (PeakPoint ⟨¯5, 1, 5, ¯9, 2⟩) ≡ 1
+u.UnitTest (PeakPoint ⟨10, 10, 10, ¯25⟩) ≡ 30
+u.UnitTest (PeakPoint ⟨3, -4, 2, 5, ¯6, 1⟩) ≡ 6
+u.UnitTest (PeakPoint ⟨¯1, -2, -3, -4⟩) ≡ 0
+u.UnitTest (PeakPoint ⟨¯10, 15, 5⟩) ≡ 10
diff --git a/challenge-340/ash/raku/ch-1.raku b/challenge-340/ash/raku/ch-1.raku
new file mode 100644
index 0000000000..1bd8d01199
--- /dev/null
+++ b/challenge-340/ash/raku/ch-1.raku
@@ -0,0 +1,13 @@
+# Task 1 of the Weekly Challenge 340
+# https://theweeklychallenge.org/blog/perl-weekly-challenge-340/#TASK1
+
+say redup('abbaca'); # ca
+say redup('azxxzy'); # ay
+say redup('aaaaaaaa'); # ''
+say redup('aabccba'); # a
+say redup('abcddcba'); # ''
+
+sub redup($str is copy) {
+ while $str ~~ s:g/(.) $0// {};
+ return $str;
+}
diff --git a/challenge-340/ash/raku/ch-2.raku b/challenge-340/ash/raku/ch-2.raku
new file mode 100644
index 0000000000..caa4c3a5de
--- /dev/null
+++ b/challenge-340/ash/raku/ch-2.raku
@@ -0,0 +1,12 @@
+# Task 2 of the Weekly Challenge 340
+# https://theweeklychallenge.org/blog/perl-weekly-challenge-340/#TASK2
+
+say is-increasing('The cat has 3 kittens 7 toys 10 beds'); # True
+say is-increasing('Alice bought 5 apples 2 oranges 9 bananas'); # False
+say is-increasing('I ran 1 mile 2 days 3 weeks 4 months'); # True
+say is-increasing('Bob has 10 cars 10 bikes'); # False
+say is-increasing('Zero is 0 one is 1 two is 2'); # True
+
+sub is-increasing($str) {
+ [<] $str.comb(/\d+/)
+}
diff --git a/challenge-340/bob-lied/README.md b/challenge-340/bob-lied/README.md
index 373adf6206..ea96334263 100644
--- a/challenge-340/bob-lied/README.md
+++ b/challenge-340/bob-lied/README.md
@@ -1,5 +1,5 @@
-# Solutions to weekly challenge 339 by Bob Lied
+# Solutions to weekly challenge 340 by Bob Lied
-## [PWC](https://perlweeklychallenge.org/blog/perl-weekly-challenge-339/)
-## [GitHub](https://github.com/boblied/perlweeklychallenge-club/tree/master/challenge-339/bob-lied)
-[Blog](https://dev.to/boblied/pwc-339-max-diff-sorting-for-the-win-43c8)
+## [PWC](https://perlweeklychallenge.org/blog/perl-weekly-challenge-340/)
+## [GitHub](https://github.com/boblied/perlweeklychallenge-club/tree/master/challenge-340/bob-lied)
+[Blog](https://dev.to/boblied/)
diff --git a/challenge-340/bob-lied/perl/ch-1.pl b/challenge-340/bob-lied/perl/ch-1.pl
new file mode 100644
index 0000000000..181939cbfe
--- /dev/null
+++ b/challenge-340/bob-lied/perl/ch-1.pl
@@ -0,0 +1,60 @@
+#!/usr/bin/env perl
+# vim:set ts=4 sw=4 sts=4 et ai wm=0 nu:
+#=============================================================================
+# Copyright (c) 2025, Bob Lied
+#=============================================================================
+# ch-1.pl Perl Weekly Challenge 340 Task 1 Duplicate Removals
+#=============================================================================
+# You are given a string, $str, consisting of lowercase English letters.
+# Write a script to return the final string after all duplicate removals
+# have been made. Repeat duplicate removals on the given string until we
+# no longer can. A duplicate removal consists of choosing two adjacent
+# and equal letters and removing them.
+#
+# Example 1 Input: $str = 'abbaca'
+# Output: 'ca'
+# Step 1: Remove 'bb' => 'aaca'
+# Step 2: Remove 'aa' => 'ca'
+# Example 2 Input: $str = 'azxxzy'
+# Output: 'ay'
+# Example 3 Input: $str = 'aaaaaaaa'
+# Output: ''
+# Example 4 Input: $str = 'aabccba'
+# Output: 'a'
+# Example 5 Input: $str = 'abcddcba'
+# Output: ''
+#=============================================================================
+
+use v5.42;
+
+
+use Getopt::Long;
+my $Verbose = false;
+my $DoTest = false;
+
+GetOptions("test" => \$DoTest, "verbose" => \$Verbose);
+#=============================================================================
+
+exit(!runTest()) if $DoTest;
+
+say dupRmv($_) for @ARGV;
+
+#=============================================================================
+sub dupRmv($str)
+{
+ while ( $str =~ s/(.)\1//g ) { }
+ return $str;
+}
+
+sub runTest
+{
+ use Test2::V0;
+
+ is( dupRmv('abbaca'), 'ca', "Example 1");
+ is( dupRmv('azxxzy'), 'ay', "Example 2");
+ is( dupRmv('aaaaaaaa'), '', "Example 3");
+ is( dupRmv('aabccba'), 'a', "Example 4");
+ is( dupRmv('abcddcba'), '', "Example 5");
+
+ done_testing;
+}
diff --git a/challenge-340/bob-lied/perl/ch-2.pl b/challenge-340/bob-lied/perl/ch-2.pl
new file mode 100644
index 0000000000..162a3b8b91
--- /dev/null
+++ b/challenge-340/bob-lied/perl/ch-2.pl
@@ -0,0 +1,137 @@
+#!/usr/bin/env perl
+# vim:set ts=4 sw=4 sts=4 et ai wm=0 nu:
+#=============================================================================
+# Copyright (c) 2025, Bob Lied
+#=============================================================================
+# ch-2.pl Perl Weekly Challenge 340 Task 2 Ascending Numbers
+#=============================================================================
+# You are given a string, $str, is a list of tokens separated by a single
+# space. Every token is either a positive number consisting of digits 0-9
+# with no leading zeros, or a word consisting of lowercase English letters.
+# Write a script to check if all the numbers in the given string are strictly
+# increasing from left to right.
+# Example 1 Input: $str = "The cat has 3 kittens 7 toys 10 beds"
+# Output: true
+# Example 2 Input: $str = 'Alice bought 5 apples 2 oranges 9 bananas'
+# Output: false
+# Example 3 Input: $str = 'I ran 1 mile 2 days 3 weeks 4 months'
+# Output: true
+# Example 4 Input: $str = 'Bob has 10 cars 10 bikes'
+# Output: false
+# Example 5 Input: $str = 'Zero is 0 one is 1 two is 2'
+# Output: true
+#=============================================================================
+
+use v5.42;
+
+
+use Getopt::Long;
+my $Verbose = false;
+my $DoTest = false;
+my $Benchmark = 0;
+
+GetOptions("test" => \$DoTest, "verbose" => \$Verbose, "benchmark:i" => \$Benchmark);
+my $logger;
+{
+ use Log::Log4perl qw(:easy);
+ Log::Log4perl->easy_init({ level => ($Verbose ? $DEBUG : $INFO ),
+ layout => "%d{HH:mm:ss.SSS} %p{1} %m%n" });
+ $logger = Log::Log4perl->get_logger();
+}
+#=============================================================================
+
+exit(!runTest()) if $DoTest;
+exit( runBenchmark($Benchmark) ) if $Benchmark;
+
+say (isAscending($_) ? "true" : "false") for @ARGV;
+
+#=============================================================================
+sub isAscending($str)
+{
+ my $isSorted = true;
+ my @num = grep /^\d+$/, split(" ", $str);
+ while ( defined(my $n = shift @num) && @num)
+ {
+ $isSorted &&= ($n < $num[0]);
+ }
+ return $isSorted;
+ # I'm taking the position that all lists are ascending unless
+ # proved otherwise, hence a list of 0 or 1 returns true.
+}
+
+sub isAscending_slide($str)
+{
+ use List::MoreUtils qw/slide/; use List::Util qw/all/;
+ my @num = grep /^\d+$/, split(" ", $str);
+ return (@num < 2 ? true : all { $_ } slide { $a < $b } @num);
+}
+
+sub isAscending_try($str)
+{
+ use List::MoreUtils qw/slide/; use List::Util qw/all/;
+ # Slide will throw if it doesn't have at least 2 elements to work on.
+ try {
+ all { $_ } slide { $a < $b } grep /^\d+$/, split(" ", $str);
+ }
+ catch ( $e ) {
+ return ($e =~ m/slide/);
+ }
+}
+
+sub runTest
+{
+ use Test2::V0;
+
+ my @func = (
+ [ loop => \&isAscending ],
+ [ slide => \&isAscending_slide ],
+ [ trycatch => \&isAscending_try ],
+ );
+
+ my @case = (
+ ['The cat has 3 kittens 7 toys 10 beds', true, "Example 1" ],
+ ['Alice bought 5 apples 2 oranges 9 bananas', false, "Example 2" ],
+ ['I ran 1 mile 2 days 3 weeks 4 months', true, "Example 3" ],
+ ['Bob has 10 cars 10 bikes', false, "Example 4" ],
+ ['Zero is 0 one is 1 two is 2', true, "Example 5" ],
+ ['no numbers here', true, "Zero numbers" ],
+ ['1 number here', true, "One numbers" ],
+ ['is this7a number9', true, "All really numbers, empty" ],
+ ['is 7 this8a number9 2', false, "Some not really numbers" ],
+ );
+
+ for ( @func )
+ {
+ my ($name, $subref) = $_->@*;
+ foreach ( @case )
+ {
+ my ($arg, $expect, $comment) = $_->@*;
+ is( $subref->($arg), $expect, "$name $comment");
+ }
+ }
+
+ done_testing;
+}
+
+sub runBenchmark($repeat)
+{
+ use Benchmark qw/cmpthese/;
+
+ my @str = (
+ 'The cat has 3 kittens 7 toys 10 beds',
+ 'Alice bought 5 apples 2 oranges 9 bananas',
+ 'I ran 1 mile 2 days 3 weeks 4 months Bob has 10 cars 10 bikes',
+ 'Zero is 0 one is 1 two is 2 three is 3 four is 4 five is 5 six is 6',
+ 'no numbers here',
+ '1 number here',
+ 'is this7a number9',
+ 'is 7 this8a number9 2',
+
+ join(" and ", 0..99),
+ );
+ cmpthese($repeat, {
+ loop => sub { isAscending($_) for @str },
+ slide => sub { isAscending_slide($_) for @str },
+ trycatch => sub { isAscending_try($_) for @str },
+ });
+}
diff --git a/challenge-340/conor-hoekstra/ch-1.bqn b/challenge-340/conor-hoekstra/ch-1.bqn
new file mode 100644
index 0000000000..c43f038cd2
--- /dev/null
+++ b/challenge-340/conor-hoekstra/ch-1.bqn
@@ -0,0 +1,14 @@
+# For up to date code:
+# https://github.com/codereport/bqn-code/blob/main/pwc/340-1.bqn
+
+u ⇐ •Import "/home/cph/bqn-test/test.bqn"
+fn ⇐ •Import "/home/cph/bqn-code/lib/fun.bqn"
+
+RemoveDuplicates ← (∾·(1<≠)◶⟨⊢,2⊸↓⟩¨fn.Group)⍟≠
+
+# Tests
+u.UnitTest (RemoveDuplicates "abbaca") ≡ "ca"
+u.UnitTest (RemoveDuplicates "azxxzy") ≡ "ay"
+u.UnitTest (RemoveDuplicates "aaaaaaaa") ≡ ""
+u.UnitTest (RemoveDuplicates "aabccba") ≡ "a"
+u.UnitTest (RemoveDuplicates "abcddcba") ≡ ""
diff --git a/challenge-340/conor-hoekstra/ch-2.bqn b/challenge-340/conor-hoekstra/ch-2.bqn
new file mode 100644
index 0000000000..904f0729c4
--- /dev/null
+++ b/challenge-340/conor-hoekstra/ch-2.bqn
@@ -0,0 +1,15 @@
+# For up to date code:
+# https://github.com/codereport/bqn-code/blob/main/pwc/340-2.bqn
+
+u ⇐ •Import "/home/cph/bqn-test/test.bqn"
+s ⇐ •Import "/home/cph/bqn-code/lib/string.bqn"
+fn ⇐ •Import "/home/cph/bqn-code/lib/fun.bqn"
+
+AscendingNumbers ← ∧´0<·fn.Deltas s.Nats
+
+# Tests
+u.UnitTest (AscendingNumbers "The cat has 3 kittens 7 toys 10 beds") ≡ 1
+u.UnitTest (AscendingNumbers "Alice bought 5 apples 2 oranges 9 bananas") ≡ 0
+u.UnitTest (AscendingNumbers "I ran 1 mile 2 days 3 weeks 4 months") ≡ 1
+u.UnitTest (AscendingNumbers "Bob has 10 cars 10 bikes") ≡ 0
+u.UnitTest (AscendingNumbers "Zero is 0 one is 1 two is 2") ≡ 1
diff --git a/challenge-340/e-choroba/perl/ch-1.pl b/challenge-340/e-choroba/perl/ch-1.pl
new file mode 100755
index 0000000000..7704ac07aa
--- /dev/null
+++ b/challenge-340/e-choroba/perl/ch-1.pl
@@ -0,0 +1,20 @@
+#!/usr/bin/perl
+use warnings;
+use strict;
+use experimental qw( signatures );
+
+sub duplicate_removals($str) {
+ 1 while $str =~ s/(.)\1//g;
+ return $str
+}
+
+use Test::More tests => 5 + 2;
+
+is duplicate_removals('abbaca'), 'ca', 'Example 1';
+is duplicate_removals('azxxzy'), 'ay', 'Example 2';
+is duplicate_removals('aaaaaaaa'), "", 'Example 3';
+is duplicate_removals('aabccba'), 'a', 'Example 4';
+is duplicate_removals('abcddcba'), "", 'Example 5';
+
+is duplicate_removals('aaa'), 'a', 'Odd length';
+is duplicate_removals('aabccdeedffbgg'), "", 'Many steps';
diff --git a/challenge-340/e-choroba/perl/ch-2.pl b/challenge-340/e-choroba/perl/ch-2.pl
new file mode 100755
index 0000000000..8df9da1ad3
--- /dev/null
+++ b/challenge-340/e-choroba/perl/ch-2.pl
@@ -0,0 +1,34 @@
+#!/usr/bin/perl
+use warnings;
+use strict;
+use experimental qw( signatures );
+
+sub ascending_numbers($str) {
+ my @numbers = $str =~ /(\d+)/ag;
+ for my $i (1 .. $#numbers) {
+ return if $numbers[$i] <= $numbers[ $i - 1 ];
+ }
+ return 1
+}
+
+use constant { true => !0, false => !1 };
+use Test2::V0;
+plan(5 + 1);
+
+is ascending_numbers('The cat has 3 kittens 7 toys 10 beds'),
+ bool(true),
+ 'Example 1';
+is ascending_numbers('Alice bought 5 apples 2 oranges 9 bananas'),
+ bool(false),
+ 'Example 2';
+is ascending_numbers('I ran 1 mile 2 days 3 weeks 4 months'),
+ bool(true),
+ 'Example 3';
+is ascending_numbers('Bob has 10 cars 10 bikes'),
+ bool(false),
+ 'Example 4';
+is ascending_numbers('Zero is 0 one is 1 two is 2'),
+ bool(true),
+ 'Example 5';
+
+is ascending_numbers('There are no numbers'), bool(true), 'No numbers';
diff --git a/challenge-340/feng-chang/raku/ch-1.raku b/challenge-340/feng-chang/raku/ch-1.raku
new file mode 100755
index 0000000000..88a82f9a9e
--- /dev/null
+++ b/challenge-340/feng-chang/raku/ch-1.raku
@@ -0,0 +1,6 @@
+#!/bin/env raku
+
+unit sub MAIN(Str:D $s is copy);
+
+$s .= subst(/(.)$0/) while $s.contains(/(.)$0/);
+put $s;
diff --git a/challenge-340/feng-chang/raku/ch-2.raku b/challenge-340/feng-chang/raku/ch-2.raku
new file mode 100755
index 0000000000..37a7400b5a
--- /dev/null
+++ b/challenge-340/feng-chang/raku/ch-2.raku
@@ -0,0 +1,5 @@
+#!/bin/env raku
+
+unit sub MAIN(Str:D $msg);
+
+put so [<] $msg.comb(/\d+/);
diff --git a/challenge-340/feng-chang/raku/test.raku b/challenge-340/feng-chang/raku/test.raku
new file mode 100755
index 0000000000..20ad3c057c
--- /dev/null
+++ b/challenge-340/feng-chang/raku/test.raku
@@ -0,0 +1,28 @@
+#!/bin/env raku
+
+# The Weekly Challenge 340
+use Test;
+
+sub pwc-test(Str:D $script, Bool :$deeply? = False, *@input) {
+ my ($expect, $assertion) = @input.splice(*-2, 2);
+ my $p = run $script, |@input, :out;
+ if $deeply {
+ is-deeply $p.out.slurp(:close).chomp.words.Bag, $expect, $assertion;
+ } else {
+ is $p.out.slurp(:close).chomp, $expect, $assertion;
+ }
+}
+
+# Task 1, Duplicate Removals
+pwc-test './ch-1.raku', 'abbaca', 'ca', 'Duplicate Removals: abbaca => ca';
+pwc-test './ch-1.raku', 'azxxzy', 'ay', 'Duplicate Removals: azxxzy => ay';
+pwc-test './ch-1.raku', 'aaaaaaaa', '', 'Duplicate Removals: aaaaaaaa => ""';
+pwc-test './ch-1.raku', 'aabccba', 'a', 'Duplicate Removals: aabccba => a';
+pwc-test './ch-1.raku', 'abcddcba', '', 'Duplicate Removals: abcddcba => ""';
+
+# Task 2, Ascending Numbers
+pwc-test './ch-2.raku', 'The cat has 3 kittens 7 toys 10 beds', 'True', 'Ascending Numbers: "The cat has 3 kittens 7 toys 10 beds" => true';
+pwc-test './ch-2.raku', 'Alice bought 5 apples 2 oranges 9 bananas', 'False', 'Ascending Numbers: "Alice bought 5 apples 2 oranges 9 bananas" => false';
+pwc-test './ch-2.raku', 'I ran 1 mile 2 days 3 weeks 4 months', 'True', 'Ascending Numbers: "I ran 1 mile 2 days 3 weeks 4 months" => true';
+pwc-test './ch-2.raku', 'Bob has 10 cars 10 bikes', 'False', 'Ascending Numbers: "Bob has 10 cars 10 bikes" => false';
+pwc-test './ch-2.raku', 'Zero is 0 one is 1 two is 2', 'True', 'Ascending Numbers: "Zero is 0 one is 1 two is 2" => Ture';
diff --git a/challenge-340/lubos-kolouch/perl/ch-1.pl b/challenge-340/lubos-kolouch/perl/ch-1.pl
new file mode 100644
index 0000000000..f466e17a75
--- /dev/null
+++ b/challenge-340/lubos-kolouch/perl/ch-1.pl
@@ -0,0 +1,52 @@
+#!/usr/bin/env perl
+use v5.38;
+use warnings;
+use feature 'signatures';
+
+=pod
+
+=head1 PURPOSE
+
+Implementation for The Weekly Challenge 340, Task 1: remove adjacent duplicate
+characters repeatedly until the string stabilises.
+
+=head1 ALGORITHM
+
+We walk the input string from left to right, using an array as a stack. Whenever
+we encounter a character matching the current stack top, we pop the stack,
+effectively discarding the duplicate pair. Otherwise, we push the character.
+When the scan completes, the stack content is the fully reduced string.
+
+=cut
+
+sub duplicate_removals ($str) {
+ _assert_plain_string($str);
+
+ my @stack;
+ for my $char ( split //, $str ) {
+ if ( @stack && $stack[-1] eq $char ) {
+ pop @stack;
+ }
+ else {
+ push @stack, $char;
+ }
+ }
+
+ return join q(), @stack;
+}
+
+sub _assert_plain_string ($value) {
+ die 'Input must be a defined, non-reference string'
+ if !defined $value || ref $value;
+}
+
+unless (caller) {
+ require Test::More;
+ Test::More->import( tests => 5 );
+
+ Test::More::is( duplicate_removals('abbaca'), 'ca', 'Example 1' );
+ Test::More::is( duplicate_removals('azxxzy'), 'ay', 'Example 2' );
+ Test::More::is( duplicate_removals('aaaaaaaa'), q(), 'Example 3' );
+ Test::More::is( duplicate_removals('aabccba'), 'a', 'Example 4' );
+ Test::More::is( duplicate_removals('abcddcba'), q(), 'Example 5' );
+}
diff --git a/challenge-340/lubos-kolouch/perl/ch-2.pl b/challenge-340/lubos-kolouch/perl/ch-2.pl
new file mode 100644
index 0000000000..3fe212b5c0
--- /dev/null
+++ b/challenge-340/lubos-kolouch/perl/ch-2.pl
@@ -0,0 +1,64 @@
+#!/usr/bin/env perl
+use v5.38;
+use warnings;
+use feature 'signatures';
+
+=pod
+
+=head1 PURPOSE
+
+Implementation for The Weekly Challenge 340, Task 2: decide whether the numeric
+values embedded in a space-separated token stream form a strictly increasing
+sequence.
+
+=head1 ALGORITHM
+
+We split the input on single spaces and process each token. Tokens matching the
+pattern for non-negative integers without leading zeros are interpreted as
+numbers. Each number is compared with the previously seen numeric value; the
+sequence fails if we ever see a decrease or plateau. If no violation occurs, the
+sequence is strictly increasing.
+
+=cut
+
+sub ascending_numbers ($str) {
+ _assert_plain_string($str);
+
+ my $last;
+ for my $token ( split / /, $str ) {
+ next unless _is_valid_integer_token($token);
+
+ my $value = 0 + $token;
+ return 0 if defined $last && $value <= $last;
+ $last = $value;
+ }
+
+ return 1;
+}
+
+sub _is_valid_integer_token ($token) {
+ return $token eq '0' || $token =~ /\A[1-9]\d*\z/;
+}
+
+sub _assert_plain_string ($value) {
+ die 'Input must be a defined, non-reference string'
+ if !defined $value || ref $value;
+}
+
+sub _bool_to_text ($bool) {
+ return $bool ? 'true' : 'false';
+}
+