From 99d8f21a44e0ee6239d6d9ca105c671ec3db7214 Mon Sep 17 00:00:00 2001 From: Lubos Kolouch Date: Mon, 22 Sep 2025 12:47:38 +0200 Subject: Challenge 340 LK Perl Python --- challenge-340/lubos-kolouch/perl/ch-1.pl | 52 ++++++++++++++++++++++++ challenge-340/lubos-kolouch/perl/ch-2.pl | 64 ++++++++++++++++++++++++++++++ challenge-340/lubos-kolouch/python/ch-1.py | 53 +++++++++++++++++++++++++ challenge-340/lubos-kolouch/python/ch-2.py | 54 +++++++++++++++++++++++++ 4 files changed, 223 insertions(+) create mode 100644 challenge-340/lubos-kolouch/perl/ch-1.pl create mode 100644 challenge-340/lubos-kolouch/perl/ch-2.pl create mode 100644 challenge-340/lubos-kolouch/python/ch-1.py create mode 100644 challenge-340/lubos-kolouch/python/ch-2.py 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'; +} + +unless (caller) { + require Test::More; + Test::More->import( tests => 5 ); + + Test::More::is( _bool_to_text( ascending_numbers('The cat has 3 kittens 7 toys 10 beds') ), + 'true', 'Example 1' ); + Test::More::is( _bool_to_text( ascending_numbers('Alice bought 5 apples 2 oranges 9 bananas') ), + 'false', 'Example 2' ); + Test::More::is( _bool_to_text( ascending_numbers('I ran 1 mile 2 days 3 weeks 4 months') ), + 'true', 'Example 3' ); + Test::More::is( _bool_to_text( ascending_numbers('Bob has 10 cars 10 bikes') ), 'false', 'Example 4' ); + Test::More::is( _bool_to_text( ascending_numbers('Zero is 0 one is 1 two is 2') ), 'true', 'Example 5' ); +} diff --git a/challenge-340/lubos-kolouch/python/ch-1.py b/challenge-340/lubos-kolouch/python/ch-1.py new file mode 100644 index 0000000000..ba06cfdf20 --- /dev/null +++ b/challenge-340/lubos-kolouch/python/ch-1.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 +"""Solutions for The Weekly Challenge 340, Task 1 (Duplicate Removals). + +The task asks for repeatedly deleting adjacent identical characters from a +lowercase string until no such pair remains. This implementation exposes the +core routine for reuse and embeds unit tests based solely on the official +examples. +""" + +from __future__ import annotations + +import unittest + + +def duplicate_removals(text: str) -> str: + """Return the fully reduced form of *text* after removing adjacent duplicates. + + The algorithm processes the characters left to right while maintaining a + stack (implemented as a Python list). A character equal to the current stack + top cancels out the pair; otherwise the character is added to the stack. The + final stack contents yield the reduced string. + """ + + stack: list[str] = [] + for char in text: + if stack and stack[-1] == char: + stack.pop() + else: + stack.append(char) + return "".join(stack) + + +class DuplicateRemovalsTests(unittest.TestCase): + """Exercises the routine against the provided examples.""" + + def test_example_1(self) -> None: + self.assertEqual(duplicate_removals("abbaca"), "ca") + + def test_example_2(self) -> None: + self.assertEqual(duplicate_removals("azxxzy"), "ay") + + def test_example_3(self) -> None: + self.assertEqual(duplicate_removals("aaaaaaaa"), "") + + def test_example_4(self) -> None: + self.assertEqual(duplicate_removals("aabccba"), "a") + + def test_example_5(self) -> None: + self.assertEqual(duplicate_removals("abcddcba"), "") + + +if __name__ == "__main__": + unittest.main() diff --git a/challenge-340/lubos-kolouch/python/ch-2.py b/challenge-340/lubos-kolouch/python/ch-2.py new file mode 100644 index 0000000000..554e36abd5 --- /dev/null +++ b/challenge-340/lubos-kolouch/python/ch-2.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +"""Solutions for The Weekly Challenge 340, Task 2 (Ascending Numbers). + +The challenge provides a space-separated string containing words and positive +integers without leading zeros. The goal is to determine whether the numeric +subsequence appears in strictly increasing order. Only the official examples +are used for verification, as required. +""" + +from __future__ import annotations + +import unittest + + +def ascending_numbers(text: str) -> bool: + """Return ``True`` if the numbers inside *text* increase strictly.""" + + last_value: int | None = None + for token in text.split(" "): + if not token.isdigit(): + continue + + value = int(token) + if last_value is not None and value <= last_value: + return False + last_value = value + + return True + + +class AscendingNumbersTests(unittest.TestCase): + """Exercises the routine against the provided examples.""" + + def test_example_1(self) -> None: + self.assertTrue( + ascending_numbers("The cat has 3 kittens 7 toys 10 beds")) + + def test_example_2(self) -> None: + self.assertFalse( + ascending_numbers("Alice bought 5 apples 2 oranges 9 bananas")) + + def test_example_3(self) -> None: + self.assertTrue( + ascending_numbers("I ran 1 mile 2 days 3 weeks 4 months")) + + def test_example_4(self) -> None: + self.assertFalse(ascending_numbers("Bob has 10 cars 10 bikes")) + + def test_example_5(self) -> None: + self.assertTrue(ascending_numbers("Zero is 0 one is 1 two is 2")) + + +if __name__ == "__main__": + unittest.main() -- cgit