aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLubos Kolouch <lubos@kolouch.net>2025-11-02 12:35:07 +0100
committerLubos Kolouch <lubos@kolouch.net>2025-11-02 12:35:07 +0100
commit6363919707478d0f04dc8bd0793d013389e3d4dc (patch)
tree5c1d92b06a4374d6d1b679101f96a5b795dcea0f
parentbaad0f5cfae9afface6025d07875ee5c61a7f7ea (diff)
downloadperlweeklychallenge-club-6363919707478d0f04dc8bd0793d013389e3d4dc.tar.gz
perlweeklychallenge-club-6363919707478d0f04dc8bd0793d013389e3d4dc.tar.bz2
perlweeklychallenge-club-6363919707478d0f04dc8bd0793d013389e3d4dc.zip
Add Perl and Python solutions for challenge 331
-rw-r--r--challenge-331/lubos-kolouch/perl/ch-1.pl39
-rw-r--r--challenge-331/lubos-kolouch/perl/ch-2.pl65
-rw-r--r--challenge-331/lubos-kolouch/python/ch-1.py41
-rw-r--r--challenge-331/lubos-kolouch/python/ch-2.py61
4 files changed, 206 insertions, 0 deletions
diff --git a/challenge-331/lubos-kolouch/perl/ch-1.pl b/challenge-331/lubos-kolouch/perl/ch-1.pl
new file mode 100644
index 0000000000..64a049ad6c
--- /dev/null
+++ b/challenge-331/lubos-kolouch/perl/ch-1.pl
@@ -0,0 +1,39 @@
+#!/usr/bin/env perl
+use strict;
+use warnings;
+use feature qw(signatures state);
+no warnings qw(experimental::signatures);
+use Type::Params qw(compile);
+use Types::Standard qw(Str);
+use Test::More;
+
+=pod
+
+=head1 PURPOSE
+
+Return the length of the final word in a string, ignoring any leading or
+trailing whitespace. Words are sequences of non-whitespace characters.
+
+=head1 ALGORITHM
+
+We validate the argument with L<Type::Params> to ensure a defined string. The
+string is scanned for word tokens using a regular expression; if at least one
+word is found we report the length of the final token, otherwise we return zero.
+
+=cut
+
+## no critic (Subroutines::ProhibitSubroutinePrototypes)
+sub last_word_length ($text) {
+ state $check = compile(Str);
+ my ($str) = $check->($text);
+
+ my @words = $str =~ /(\S+)/g;
+ return @words ? length( $words[-1] ) : 0;
+}
+
+# Examples supplied by the specification.
+is( last_word_length('The Weekly Challenge'), 9, 'Example 1' );
+is( last_word_length(' Hello World '), 5, 'Example 2' );
+is( last_word_length('Let\'s begin the fun'), 3, 'Example 3' );
+
+done_testing();
diff --git a/challenge-331/lubos-kolouch/perl/ch-2.pl b/challenge-331/lubos-kolouch/perl/ch-2.pl
new file mode 100644
index 0000000000..0f3f198525
--- /dev/null
+++ b/challenge-331/lubos-kolouch/perl/ch-2.pl
@@ -0,0 +1,65 @@
+#!/usr/bin/env perl
+use strict;
+use warnings;
+use feature qw(signatures state);
+no warnings qw(experimental::signatures);
+use Type::Params qw(compile);
+use Types::Standard qw(Str);
+use Test::More;
+
+=pod
+
+=head1 PURPOSE
+
+Decide whether two strings are buddy strings, i.e. whether exactly one swap of
+two characters in C<$source> can produce C<$target>. Identical strings are
+considered buddies if any character occurs more than once.
+
+=head1 ALGORITHM
+
+Inputs are validated with L<Type::Params>. If lengths differ we immediately
+return false. Otherwise we collect positions where the characters differ; more
+than two mismatches disqualify the pair. Two mismatches form buddies when the
+characters cross-match, while zero mismatches form buddies only if the string
+contains a duplicate character.
+
+=cut
+
+## no critic (Subroutines::ProhibitSubroutinePrototypes)
+sub are_buddy_strings ( $source, $target ) {
+ state $check = compile( Str, Str );
+ my ( $src, $tgt ) = $check->( $source, $target );
+
+ return 0 if length($src) != length($tgt);
+
+ my @diff;
+ for my $idx ( 0 .. length($src) - 1 ) {
+ my $s_char = substr $src, $idx, 1;
+ my $t_char = substr $tgt, $idx, 1;
+ next if $s_char eq $t_char;
+
+ push @diff, [ $s_char, $t_char ];
+ return 0 if @diff > 2;
+ }
+
+ if ( @diff == 0 ) {
+ my %seen;
+ for my $char ( split //, $src ) {
+ return 1 if ++$seen{$char} > 1;
+ }
+ return 0;
+ }
+
+ return
+ @diff == 2
+ && $diff[0][0] eq $diff[1][1]
+ && $diff[0][1] eq $diff[1][0];
+}
+
+# Examples supplied by the specification.
+is( are_buddy_strings( 'fuck', 'fcuk' ), 1, 'Example 1' );
+is( are_buddy_strings( 'love', 'love' ), 0, 'Example 2' );
+is( are_buddy_strings( 'fodo', 'food' ), 1, 'Example 3' );
+is( are_buddy_strings( 'feed', 'feed' ), 1, 'Example 4' );
+
+done_testing();
diff --git a/challenge-331/lubos-kolouch/python/ch-1.py b/challenge-331/lubos-kolouch/python/ch-1.py
new file mode 100644
index 0000000000..f4206c36fa
--- /dev/null
+++ b/challenge-331/lubos-kolouch/python/ch-1.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python3
+"""
+Task 1: Last Word
+
+Determine the length of the final word within a string, trimming any
+whitespace that may precede or follow the words. Words are contiguous
+sequences of non-whitespace characters.
+"""
+from __future__ import annotations
+
+import unittest
+
+
+def last_word_length(text: str) -> int:
+ """
+ Return the length of the last word found in `text`.
+
+ Args:
+ text: Input string that may contain leading/trailing whitespace.
+
+ Returns:
+ Length of the final word if present, otherwise zero.
+ """
+ words: list[str] = text.split()
+ return len(words[-1]) if words else 0
+
+
+class LastWordTests(unittest.TestCase):
+
+ def test_example_1(self) -> None:
+ self.assertEqual(last_word_length("The Weekly Challenge"), 9)
+
+ def test_example_2(self) -> None:
+ self.assertEqual(last_word_length(" Hello World "), 5)
+
+ def test_example_3(self) -> None:
+ self.assertEqual(last_word_length("Let's begin the fun"), 3)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/challenge-331/lubos-kolouch/python/ch-2.py b/challenge-331/lubos-kolouch/python/ch-2.py
new file mode 100644
index 0000000000..802c11154e
--- /dev/null
+++ b/challenge-331/lubos-kolouch/python/ch-2.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python3
+"""
+Task 2: Buddy Strings
+
+Given two strings of equal length, determine whether swapping a single pair of
+characters in the source string can produce the target string. Identical
+strings are considered buddies when any character appears at least twice.
+"""
+from __future__ import annotations
+
+import unittest
+
+
+def are_buddy_strings(source: str, target: str) -> bool:
+ """
+ Decide whether `source` and `target` form a pair of buddy strings.
+
+ Args:
+ source: Original string.
+ target: Desired string after at most one swap.
+
+ Returns:
+ True when a single swap (or a swap of identical characters) can make
+ the strings equal, otherwise False.
+ """
+ if len(source) != len(target):
+ return False
+
+ if source == target:
+ # Identical strings are buddies if any character repeats.
+ return len(set(source)) < len(source)
+
+ differences: list[tuple[str,
+ str]] = [(s_char, t_char)
+ for s_char, t_char in zip(source, target)
+ if s_char != t_char]
+
+ if len(differences) != 2:
+ return False
+
+ (first_source, first_target), (second_source, second_target) = differences
+ return first_source == second_target and first_target == second_source
+
+
+class BuddyStringTests(unittest.TestCase):
+
+ def test_example_1(self) -> None:
+ self.assertTrue(are_buddy_strings("fuck", "fcuk"))
+
+ def test_example_2(self) -> None:
+ self.assertFalse(are_buddy_strings("love", "love"))
+
+ def test_example_3(self) -> None:
+ self.assertTrue(are_buddy_strings("fodo", "food"))
+
+ def test_example_4(self) -> None:
+ self.assertTrue(are_buddy_strings("feed", "feed"))
+
+
+if __name__ == "__main__":
+ unittest.main()