diff options
| author | Lubos Kolouch <lubos@kolouch.net> | 2025-11-02 12:35:07 +0100 |
|---|---|---|
| committer | Lubos Kolouch <lubos@kolouch.net> | 2025-11-02 12:35:07 +0100 |
| commit | 6363919707478d0f04dc8bd0793d013389e3d4dc (patch) | |
| tree | 5c1d92b06a4374d6d1b679101f96a5b795dcea0f | |
| parent | baad0f5cfae9afface6025d07875ee5c61a7f7ea (diff) | |
| download | perlweeklychallenge-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.pl | 39 | ||||
| -rw-r--r-- | challenge-331/lubos-kolouch/perl/ch-2.pl | 65 | ||||
| -rw-r--r-- | challenge-331/lubos-kolouch/python/ch-1.py | 41 | ||||
| -rw-r--r-- | challenge-331/lubos-kolouch/python/ch-2.py | 61 |
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() |
