aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Muth <matthias.muth@gmx.de>2024-07-07 23:51:56 +0200
committerMatthias Muth <matthias.muth@gmx.de>2024-07-07 23:51:56 +0200
commit5bd24a53ad705c8e584f5123fb7228a2f9e46d5d (patch)
tree9110eb4ea9a2d8f13a942c1662a81ddbbd97a5cc
parent757bec959ede495aea7053ebae49541691b14466 (diff)
downloadperlweeklychallenge-club-5bd24a53ad705c8e584f5123fb7228a2f9e46d5d.tar.gz
perlweeklychallenge-club-5bd24a53ad705c8e584f5123fb7228a2f9e46d5d.tar.bz2
perlweeklychallenge-club-5bd24a53ad705c8e584f5123fb7228a2f9e46d5d.zip
Challenge 276 Task 1 and 2 solutions in Perl by Matthias Muth
-rw-r--r--challenge-276/matthias-muth/README.md205
-rw-r--r--challenge-276/matthias-muth/blog.txt1
-rwxr-xr-xchallenge-276/matthias-muth/perl/ch-1.pl44
-rwxr-xr-xchallenge-276/matthias-muth/perl/ch-2.pl28
4 files changed, 77 insertions, 201 deletions
diff --git a/challenge-276/matthias-muth/README.md b/challenge-276/matthias-muth/README.md
index 551d37babf..10e53d1eb9 100644
--- a/challenge-276/matthias-muth/README.md
+++ b/challenge-276/matthias-muth/README.md
@@ -1,202 +1,5 @@
-# Broken Keys and Test Driven Understanding (tm)
+**Challenge 276 solutions in Perl by Matthias Muth**
+<br/>
+(no blog post this time...)
-**Challenge 275 solutions in Perl by Matthias Muth**
-
-## Task 1: Broken Keys
-
-> You are given a sentence, $sentence and list of broken keys @keys.<br/>
-> Write a script to find out how many words can be typed fully.<br/>
-> <br/>
-> Example 1<br/>
-> Input: \$sentence = "Perl Weekly Challenge", @keys = ('l', 'a')<br/>
-> Output: 0<br/>
-> <br/>
-> Example 2<br/>
-> Input: \$sentence = "Perl and Raku", @keys = ('a')<br/>
-> Output: 1<br/>
-> Only Perl since the other word two words contain 'a' and can't be typed fully.<br/>
-> <br/>
-> Example 3<br/>
-> Input: \$sentence = "Well done Team PWC", @keys = ('l', 'o')<br/>
-> Output: 2<br/>
-> <br/>
-> Example 4<br/>
-> Input: \$sentence = "The joys of polyglottism", @keys = ('T')<br/>
-> Output: 2<br/>
-
-Regular expressions make this is an easy one.
-
-First thing, we have to separate the words in the sentence to deal with them one by one.<br/>
-No problem, just a standard call of `split " ", $sentence`.
-
-To find out whether a word contains a 'broken' key
-we can put those keys into a 'bracketed character class',
-and then check the word against that.
-For the second example above, we would try a match like this:
-
-```perl[]
- ! /[lo]/i
-```
-
-The `//i` modifier makes sure that lower or upper case doesn't matter
-(needed in the third example).
-
-So then let's combine the broken keys into a string that we can use in the regular expressions,
-and then use it for counting the matches.
-For the counting, `grep` in scalar context does the job.
-
-```perl
-sub broken_keys( $sentence, $keys ) {
- my $keys_as_string = join( "", $keys->@* );
- return scalar grep ! /[$keys_as_string]/i, split " ", $sentence;
-}
-```
-
-Et voilĂ !
-
-## Task 2: Replace Digits
-
-> You are given an alphanumeric string, \$str, where each character is either a letter or a digit.<br/>
-> Write a script to replace each digit in the given string with the value of the previous letter plus (digit) places.<br/>
-> <br/>
-> Example 1<br/>
-> Input: \$str = 'a1c1e1'<br/>
-> Ouput: 'abcdef'<br/>
-> shift('a', 1) => 'b'<br/>
-> shift('c', 1) => 'd'<br/>
-> shift('e', 1) => 'f'<br/>
-> <br/>
-> Example 2<br/>
-> Input: \$str = 'a1b2c3d4'<br/>
-> Output: 'abbdcfdh'<br/>
-> shift('a', 1) => 'b'<br/>
-> shift('b', 2) => 'd'<br/>
-> shift('c', 3) => 'f'<br/>
-> shift('d', 4) => 'h'<br/>
-> <br/>
-> Example 3<br/>
-> Input: \$str = 'b2b'<br/>
-> Output: 'bdb'<br/>
-> <br/>
-> Example 4<br/>
-> Input: \$str = 'a16z'<br/>
-> Output: 'abgz'<br/>
-
-This task is a bit more tricky. At least for me.<br/>
-Not tricky for the programming,
-but it took me an 'iterative approach' to understand the details of the specification.
-As simple (and complete and correct!) as it seems, I misunderstood it as being *too* simple.
-
-So this is my 'test driven understanding' approach.
-
-##### First try
-
-Maybe my first try was too naive.
-Repetitively match a letter and a digit,
-and then replace the digit by the properly shifted letter directly in the substitution.<br/>
-That means a `s///g` global substitution, and I added these additional 'tricks':
-
-* using the `[:alpha:]` POSIX character class to capture an upper or lower case letter,
-* using an `e` modifier to call a code block to determine the replacement string with the shifted letter,
-* using an `r` modifier to return the modified result instead of changing the input string,
-* using an `x` modifier for adding some spaces to improve readability:
-
-```perl
-sub replace_digits_1( $str ) {
- return $str =~ s{ ([[:alpha:]]) (\d) }{ $1 . chr( ord( $1 ) + $2 ) }egr;
-}
-```
-
-Great, that works well! ...
-Except for the fourth example!<br/>
-There we have two digits in a row (`'a16'`),
-and we didn't get the second digit.
-We need kind of an 'overlapping' operation.
-
-##### Second try.
-
-So next, the second approach,
-where I use an explicit loop, always restarting at the beginning of the string,
-and modifying the string itself:
-
-```perl
-sub replace_digits_2( $str ) {
- while ( $str =~
- s{ ([[:alpha:]]) (\d) }{ $1 . chr( ord( $1 ) + $2 ) }xe )
- {
- # Everything is in the loop condiiton.
- }
- return $str;
-}
-```
-
-Great, that's better!
-We catch the fourth example's second digit now, after replacing the first one.
-
-But the resulting letter for the second digit is off by one!
-
-My misunderstanding, again. Actually, we should not replace
-```perl
- 'a16' => ('a' shifted by 1 ) => 'ab6'
- 'b6' => ('b' shifted by 6 ) => 'bh'
-```
-but, in one operation:
-```perl
- 'a16' => ('a' shifted by 1 ) => 'ab6'
- ('a' shifted by 6 ) => 'abg'
-```
-
-##### So, third try:
-
-Same loop, but replacing sequences of digits from *right to left* instead of left to right.
-I capture the digits in between, and leave them for the next iterations,
-replacing the rightmost digit first:
-
-```perl
-sub replace_digits_3( $str ) {
- while ( $str =~
- s{ ([[:alpha:]]) (\d*) (\d) }{ "$1$2" . chr( ord( $1 ) + $3 ) }xe )
- {
- # Everything is in the loop condiiton.
- }
- return $str;
-}
-```
-
-Finally it works!
-
-Interesting that the bigger difficulty for me this time was not the programming itself,
-but to capture the task specification correctly.
-
-How good it is to have and use tests!
-
-##### 'Refacturing the understanding'
-
-I now understood that the task actually is not about replacing 'a letter and a digit',
-but more replacing 'a letter and a sequence of digits'.
-
-This lead me to yet another approach:<br/>
-Once the letter and *all following digits* are captured
-(using a `(\d+)` pattern), we build the replacement from
-
-- the letter itself,
-- the same letter, shifted by every digit's value.
-
-*Now* that sounds logical, of course! :-)
-
-I can turn back to the `s///g` style global substitution and avoid the `while` loop.
-Using `split` to split up the sequence of digits, and `map` to loop over the single digits.
-
-```perl
-sub replace_digits_4( $str ) {
- return $str =~ s{ ([[:alpha:]]) (\d+) }{
- join "", $1, map chr( ord( $1 ) + $_ ), split "", $2;
- }xegr;
-}
-```
-
-Probably this is my solution that best reflects the task's specification.
-
-What a funny experience this challenge was!
-
-#### **Thank you for the challenge!**
+**Thank you for the challenge!**
diff --git a/challenge-276/matthias-muth/blog.txt b/challenge-276/matthias-muth/blog.txt
new file mode 100644
index 0000000000..ca23b47aad
--- /dev/null
+++ b/challenge-276/matthias-muth/blog.txt
@@ -0,0 +1 @@
+https://github.com/MatthiasMuth/perlweeklychallenge-club/tree/muthm-276/challenge-276/matthias-muth#readme
diff --git a/challenge-276/matthias-muth/perl/ch-1.pl b/challenge-276/matthias-muth/perl/ch-1.pl
new file mode 100755
index 0000000000..077393ac37
--- /dev/null
+++ b/challenge-276/matthias-muth/perl/ch-1.pl
@@ -0,0 +1,44 @@
+#!/usr/bin/env perl
+#
+# The Weekly Challenge - Perl & Raku
+# (https://theweeklychallenge.org)
+#
+# Challenge 276 Task 1: Complete Day
+#
+# Perl solution by Matthias Muth.
+#
+
+use v5.36;
+no warnings "experimental::for_list";
+
+sub complete_day_1( @hours ) {
+ my $hits = 0;
+ for my $i ( 0..$#hours ) {
+ for my $j ( $i + 1 .. $#hours ) {
+ ++$hits
+ if ( $hours[$i] + $hours[$j] ) % 24 == 0;
+ }
+ }
+ return $hits;
+}
+
+use Math::Combinatorics;
+use List::Util qw( sum );
+
+sub complete_day_2( @hours ) {
+ return scalar grep(
+ sum( $_->@* ) % 24 == 0,
+ combine( 2, @hours )
+ );
+}
+
+*complete_day = \&complete_day_2;
+
+use Test2::V0 qw( -no_srand );
+is complete_day( 12, 12, 30, 24, 24 ), 2,
+ 'Example 1: complete_day( 12, 12, 30, 24, 24 ) == 2';
+is complete_day( 72, 48, 24, 5 ), 3,
+ 'Example 2: complete_day( 72, 48, 24, 5 ) == 3';
+is complete_day( 12, 18, 24 ), 0,
+ 'Example 3: complete_day( 12, 18, 24 ) == 0';
+done_testing;
diff --git a/challenge-276/matthias-muth/perl/ch-2.pl b/challenge-276/matthias-muth/perl/ch-2.pl
new file mode 100755
index 0000000000..cca72b9dd0
--- /dev/null
+++ b/challenge-276/matthias-muth/perl/ch-2.pl
@@ -0,0 +1,28 @@
+#!/usr/bin/env perl
+#
+# The Weekly Challenge - Perl & Raku
+# (https://theweeklychallenge.org)
+#
+# Challenge 276 Task 2: Maximum Frequency
+#
+# Perl solution by Matthias Muth.
+#
+
+use v5.36;
+
+use List::Util qw( max );
+
+sub maximum_frequency( @ints ) {
+ my %freq;
+ ++$freq{$_}
+ for @ints;
+ my $max_freq = max( values %freq );
+ return scalar grep $freq{$_} == $max_freq, @ints;
+}
+
+use Test2::V0 qw( -no_srand );
+is maximum_frequency( 1, 2, 2, 4, 1, 5 ), 4,
+ 'Example 1: maximum_frequency( 1, 2, 2, 4, 1, 5 ) == 4';
+is maximum_frequency( 1, 2, 3, 4, 5 ), 5,
+ 'Example 2: maximum_frequency( 1, 2, 3, 4, 5 ) == 5';
+done_testing;