diff options
| author | PerlMonk-Athanasius <PerlMonk.Athanasius@gmail.com> | 2022-12-03 18:42:05 +1000 |
|---|---|---|
| committer | PerlMonk-Athanasius <PerlMonk.Athanasius@gmail.com> | 2022-12-03 18:42:05 +1000 |
| commit | b653af2c9a3c70de65df6683f5de775732c07bc9 (patch) | |
| tree | 11c7cdcccf2812aaf0338d7b5e9ef4ea50dd3822 | |
| parent | 8db8a23c9c3efaeaa596f002b73f665eb561c283 (diff) | |
| download | perlweeklychallenge-club-b653af2c9a3c70de65df6683f5de775732c07bc9.tar.gz perlweeklychallenge-club-b653af2c9a3c70de65df6683f5de775732c07bc9.tar.bz2 perlweeklychallenge-club-b653af2c9a3c70de65df6683f5de775732c07bc9.zip | |
Perl & Raku solutions to Tasks 1 & 2 for Week 193
| -rw-r--r-- | challenge-193/athanasius/perl/ch-1.pl | 143 | ||||
| -rw-r--r-- | challenge-193/athanasius/perl/ch-2.pl | 291 | ||||
| -rw-r--r-- | challenge-193/athanasius/raku/ch-1.raku | 142 | ||||
| -rw-r--r-- | challenge-193/athanasius/raku/ch-2.raku | 283 |
4 files changed, 859 insertions, 0 deletions
diff --git a/challenge-193/athanasius/perl/ch-1.pl b/challenge-193/athanasius/perl/ch-1.pl new file mode 100644 index 0000000000..f0525c16a4 --- /dev/null +++ b/challenge-193/athanasius/perl/ch-1.pl @@ -0,0 +1,143 @@ +#!perl + +############################################################################### +=comment + +Perl Weekly Challenge 193 +========================= + +TASK #1 +------- +*Binary String* + +Submitted by: Mohammad S Anwar + +You are given an integer, $n > 0. + +Write a script to find all possible binary numbers of size $n. + +Example 1 + + Input: $n = 2 + Output: 00, 11, 01, 10 + +Example 2 + + Input: $n = 3 + Output: 000, 001, 010, 100, 111, 110, 101, 011 + +=cut +############################################################################### + +#--------------------------------------# +# Copyright © 2022 PerlMonk Athanasius # +#--------------------------------------# + +#============================================================================== +=comment + +Interface +--------- +If no command-line arguments are given, the test suite is run. + +=cut +#============================================================================== + +use strict; +use warnings; +use Const::Fast; +use Regexp::Common qw( number ); +use Test::More; + +const my $TEST_FLDS => 3; +const my $USAGE => +"Usage: + perl $0 <n> + perl $0 + + <n> An integer greater than zero\n"; + +#------------------------------------------------------------------------------ +BEGIN +#------------------------------------------------------------------------------ +{ + $| = 1; + print "\nChallenge 193, Task #1: Binary String (Perl)\n\n"; +} + +#============================================================================== +MAIN: +#============================================================================== +{ + my $args = scalar @ARGV; + + if ($args == 0) + { + run_tests(); + } + elsif ($args == 1) + { + my $n = $ARGV[ 0 ]; + + $n =~ / ^ $RE{num}{int} $ /x + or error( qq["$n" is not a valid integer] ); + + $n > 0 or error( qq["$n" is not positive] ); + + print "Input: \$n = $n\n"; + printf "Output: %s\n", join ', ', @{ find_binary_numbers( $n ) }; + } + else + { + error( "Expected 1 or 0 command-line arguments, found $args" ); + } +} + +#------------------------------------------------------------------------------ +sub find_binary_numbers +#------------------------------------------------------------------------------ +{ + my ($n) = @_; + my @binaries; + + for my $i (0 .. 2 ** $n - 1) + { + push @binaries, sprintf '%0*b', $n, $i; + } + + return \@binaries; +} + +#------------------------------------------------------------------------------ +sub error +#------------------------------------------------------------------------------ +{ + my ($message) = @_; + + die "ERROR: $message\n$USAGE"; +} + +#------------------------------------------------------------------------------ +sub run_tests +#------------------------------------------------------------------------------ +{ + print "Running the test suite\n"; + + while (my $line = <DATA>) + { + chomp $line; + + my ($test_name, $n, $expected) = split / , \s* /x, $line, $TEST_FLDS; + my @expected = sort split / \s+ /x, $expected; + + is_deeply( find_binary_numbers( $n ), \@expected, $test_name ); + } + + done_testing; +} + +############################################################################### + +__DATA__ +Example 1, 2, 00 11 01 10 +Example 2, 3, 000 001 010 100 111 110 101 011 diff --git a/challenge-193/athanasius/perl/ch-2.pl b/challenge-193/athanasius/perl/ch-2.pl new file mode 100644 index 0000000000..0396ac5bd2 --- /dev/null +++ b/challenge-193/athanasius/perl/ch-2.pl @@ -0,0 +1,291 @@ +#!perl + +############################################################################### +=comment + +Perl Weekly Challenge 193 +========================= + +TASK #2 +------- +*Odd String* + +Submitted by: Mohammad S Anwar + +You are given a list of strings of same length, @s. + +Write a script to find the odd string in the given list. Use positional value +of alphabet starting with 0, i.e. a = 0, b = 1, ... z = 25. + + Find the difference array for each string as shown in the example. Then + pick the odd one out. + +Example 1: + + Input: @s = ("adc", "wzy", "abc") + Output: "abc" + + Difference array for "adc" => [ d - a, c - d ] + => [ 3 - 0, 2 - 3 ] + => [ 3, -1 ] + + Difference array for "wzy" => [ z - w, y - z ] + => [ 25 - 22, 24 - 25 ] + => [ 3, -1 ] + + Difference array for "abc" => [ b - a, c - b ] + => [ 1 - 0, 2 - 1 ] + => [ 1, 1 ] + + The difference array for "abc" is the odd one. + +Example 2: + + Input: @s = ("aaa", "bob", "ccc", "ddd") + Output: "bob" + + Difference array for "aaa" => [ a - a, a - a ] + => [ 0 - 0, 0 - 0 ] + => [ 0, 0 ] + + Difference array for "bob" => [ o - b, b - o ] + => [ 14 - 1, 1 - 14 ] + => [ 13, -13 ] + + Difference array for "ccc" => [ c - c, c - c ] + => [ 2 - 2, 2 - 2 ] + => [ 0, 0 ] + + Difference array for "ddd" => [ d - d, d - d ] + => [ 3 - 3, 3 - 3 ] + => [ 0, 0 ] + + The difference array for "bob" is the odd one. + +=cut +############################################################################### + +#--------------------------------------# +# Copyright © 2022 PerlMonk Athanasius # +#--------------------------------------# + +#============================================================================== +=comment + +Interface +--------- +1. If no command-line arguments are given, the test suite is run. +2. To show the difference array for each string, set $VERBOSE to a true value. + (This has no effect on the running of the test suite.) + +Assumptions +----------- +1. The input list contains at least three strings. +2. Valid input strings are non-empty, and consist of lower case letters only. + +=cut +#============================================================================== + +use strict; +use warnings; +use Const::Fast; +use Test::More; + +const my $TEST_FLDS => 3; +const my $VERBOSE => 1; +const my $USAGE => +"Usage: + perl $0 [<s> ...] + perl $0 + + [<s> ...] A list of 3+ same-length strings of lower case letters\n"; + +#------------------------------------------------------------------------------ +BEGIN +#------------------------------------------------------------------------------ +{ + $| = 1; + print "\nChallenge 193, Task #2: Odd String (Perl)\n\n"; +} + +#============================================================================== +MAIN: +#============================================================================== +{ + my $args = scalar @ARGV; + + if ($args == 0) + { + run_tests(); + } + elsif ($args < 3) + { + error( "Expected 0 or 3+ arguments, found $args" ); + } + else + { + my @s = @ARGV; + my $s0 = $s[ 0 ]; + my $len = length $s0; + + for my $s (@s) + { + $s =~ / ^ [a-z]+ $ /x + or error( qq["$s" is not a valid string] ); + + length $s == $len + or error( qq[Strings "$s0" and "$s" have different lengths] ); + } + + printf "Input: \@s = (%s)\n", join ', ', map { qq["$_"] } @s; + + my ($odd, $diffs) = find_odd_string( \@s ); + + print "Output: $odd\n"; + + print_diff_arrays( $diffs ) if $VERBOSE; + } +} + +#------------------------------------------------------------------------------ +sub find_odd_string +#------------------------------------------------------------------------------ +{ + my ($s) = @_; + my $diffs = get_all_diff_arrays( $s ); + my $odd = 'None'; + my $elems = scalar @$s; + my $ndiffs = scalar keys %$diffs; + my $done = 0; + + if ($ndiffs == 1) + { + $odd .= " (all $elems strings have the same difference array)"; + $done = 1; + } + elsif ($ndiffs == 2) + { + for my $list (values %$diffs) + { + if (scalar @$list == 1) + { + $odd = '"' . $list->[ 0 ] . '"'; + $done = 1; + last; + } + } + } + + $odd .= " (the $elems strings have $ndiffs distinct difference arrays)" + unless $done; + + return ($odd, $diffs); +} + +#------------------------------------------------------------------------------ +sub get_all_diff_arrays +#------------------------------------------------------------------------------ +{ + my ($s) = @_; + my %diff_arrays; + + for my $str (@$s) + { + my $diffs = get_one_diff_array( $str ); + my $gist = '[ ' . join( ', ', @$diffs ) . ' ]'; + + push @{ $diff_arrays{ $gist } }, $str; + } + + return \%diff_arrays; +} + +#------------------------------------------------------------------------------ +sub get_one_diff_array +#------------------------------------------------------------------------------ +{ + my ($str) = @_; + my @chars = split //, $str; + my @diffs; + + for my $i (1 .. length( $str ) - 1) + { + push @diffs, ord( $chars[ $i ] ) - ord( $chars[ $i - 1 ] ); + } + + return \@diffs; +} + +#------------------------------------------------------------------------------ +sub print_diff_arrays +#------------------------------------------------------------------------------ +{ + my ($da2strs) = @_; + my %str2da; + + while (my ($key, $value) = each %$da2strs) # Reverse the hash + { + for my $str (@$value) + { + $str2da{ $str } = $key; + } + } + + print "\n Difference arrays:\n"; + + for my $str (sort keys %str2da) + { + printf qq[ "%s" => %s\n], $str, $str2da{ $str }; + } +} + +#------------------------------------------------------------------------------ +sub error +#------------------------------------------------------------------------------ +{ + my ($message) = @_; + + die "ERROR: $message\n$USAGE"; +} + +#------------------------------------------------------------------------------ +sub run_tests +#------------------------------------------------------------------------------ +{ + print "Running the test suite\n"; + + while (my $line = <DATA>) + { + chomp $line; + + if ($line =~ s/ \\ $ //x) + { + $line .= <DATA>; + redo; + } + + my ($test_name, $in, $expected) = split / , \s* /x, $line, $TEST_FLDS; + + my @list = split / \s+ /x, $in; + + my ($odd, undef) = find_odd_string( \@list ); + + is $odd, $expected, $test_name; + } + + done_testing; +} + +############################################################################### + +__DATA__ +Example 1, adc wzy abc, abc +Example 2, aaa bob ccc ddd, bob +All same, adc wzy vyx bed, \ + None (all 4 strings have the same difference array) +Two odd, mor jlo abc def, \ + None (the 4 strings have 2 distinct difference arrays) +All odd, abc acd ade aef afg, \ + None (the 5 strings have 5 distinct difference arrays) +Odd plus, adc wzy abc jop kpq, \ + None (the 5 strings have 3 distinct difference arrays) diff --git a/challenge-193/athanasius/raku/ch-1.raku b/challenge-193/athanasius/raku/ch-1.raku new file mode 100644 index 0000000000..e9ea9cae76 --- /dev/null +++ b/challenge-193/athanasius/raku/ch-1.raku @@ -0,0 +1,142 @@ +use v6d; + +############################################################################### +=begin comment + +Perl Weekly Challenge 193 +========================= + +TASK #1 +------- +*Binary String* + +Submitted by: Mohammad S Anwar + +You are given an integer, $n > 0. + +Write a script to find all possible binary numbers of size $n. + +Example 1 + + Input: $n = 2 + Output: 00, 11, 01, 10 + +Example 2 + + Input: $n = 3 + Output: 000, 001, 010, 100, 111, 110, 101, 011 + +=end comment +############################################################################### + +#--------------------------------------# +# Copyright © 2022 PerlMonk Athanasius # +#--------------------------------------# + +#============================================================================== +=begin comment + +Interface +--------- +If no command-line arguments are given, the test suite is run. + +=end comment +#============================================================================== + +use Test; + +subset Pos of Int where * > 0; + +my UInt constant $TEST-FIELDS = 3; + +#------------------------------------------------------------------------------ +BEGIN +#------------------------------------------------------------------------------ +{ + "\nChallenge 193, Task #1: Binary String (Raku)\n".put; +} + +#============================================================================== +multi sub MAIN +( + Pos:D $n #= An integer greater than zero +) +#============================================================================== +{ + "Input: \$n = $n".put; + "Output: %s\n".printf: find-binary-numbers( $n ).join: ', '; +} + +#============================================================================== +multi sub MAIN() # No input: run the test suite +#============================================================================== +{ + run-tests(); +} + +#------------------------------------------------------------------------------ +sub find-binary-numbers( Pos:D $n --> List:D[Str:D] ) +#------------------------------------------------------------------------------ +{ + my Str @binaries; + + for 0 .. 2 ** $n - 1 -> UInt $i + { + @binaries.push: '%0*b'.sprintf: $n, $i; + } + + return @binaries; +} + +#------------------------------------------------------------------------------ +sub run-tests() +#------------------------------------------------------------------------------ +{ + 'Running the test suite'.put; + + for test-data.lines -> Str $line + { + my Str ($test-name, $n, $expected) = + $line.split: / \, \s* /, $TEST-FIELDS, :skip-empty; + + my Str @expected = $expected.split( / \s+ /, :skip-empty ).sort; + + is-deeply( find-binary-numbers( $n.Int ), @expected, $test-name ); + } + + done-testing; +} + +#------------------------------------------------------------------------------ +sub test-data( --> Str:D ) +#------------------------------------------------------------------------------ +{ + return q:to/END/; + Example 1, 2, 00 11 01 10 + Example 2, 3, 000 001 010 100 111 110 101 011 + END +} + +#------------------------------------------------------------------------------ +sub error( Str:D $message ) +#------------------------------------------------------------------------------ +{ + "ERROR: $message".put; + + USAGE(); + + exit 0; +} + +#------------------------------------------------------------------------------ +sub USAGE() +#------------------------------------------------------------------------------ +{ + my Str $usage = $*USAGE; + + $usage ~~ s:g/ ($*PROGRAM-NAME) /raku $0/; + + $usage.put; +} + +############################################################################### diff --git a/challenge-193/athanasius/raku/ch-2.raku b/challenge-193/athanasius/raku/ch-2.raku new file mode 100644 index 0000000000..94474684b3 --- /dev/null +++ b/challenge-193/athanasius/raku/ch-2.raku @@ -0,0 +1,283 @@ +use v6d; + +############################################################################### +=begin comment + +Perl Weekly Challenge 193 +========================= + +TASK #2 +------- +*Odd String* + +Submitted by: Mohammad S Anwar + +You are given a list of strings of same length, @s. + +Write a script to find the odd string in the given list. Use positional value +of alphabet starting with 0, i.e. a = 0, b = 1, ... z = 25. + + Find the difference array for each string as shown in the example. Then + pick the odd one out. + +Example 1: + + Input: @s = ("adc", "wzy", "abc") + Output: "abc" + + Difference array for "adc" => [ d - a, c - d ] + => [ 3 - 0, 2 - 3 ] + => [ 3, -1 ] + + Difference array for "wzy" => [ z - w, y - z ] + => [ 25 - 22, 24 - 25 ] + => [ 3, -1 ] + + Difference array for "abc" => [ b - a, c - b ] + => [ 1 - 0, 2 - 1 ] + => [ 1, 1 ] + + The difference array for "abc" is the odd one. + +Example 2: + + Input: @s = ("aaa", "bob", "ccc", "ddd") + Output: "bob" + + Difference array for "aaa" => [ a - a, a - a ] + => [ 0 - 0, 0 - 0 ] + => [ 0, 0 ] + + Difference array for "bob" => [ o - b, b - o ] + => [ 14 - 1, 1 - 14 ] + => [ 13, -13 ] + + Difference array for "ccc" => [ c - c, c - c ] + => [ 2 - 2, 2 - 2 ] + => [ 0, 0 ] + + Difference array for "ddd" => [ d - d, d - d ] + => [ 3 - 3, 3 - 3 ] + => [ 0, 0 ] + + The difference array for "bob" is the odd one. + +=end comment +############################################################################### + +#--------------------------------------# +# Copyright © 2022 PerlMonk Athanasius # +#--------------------------------------# + +#============================================================================== +=begin comment + +Interface +--------- +1. If no command-line arguments are given, the test suite is run. +2. To show the difference array for each string, set $VERBOSE to True. (This + has no effect on the running of the test suite.) + +Assumptions +----------- +1. The input list contains at least three strings. +2. Valid input strings are non-empty, and consist of lower case letters only. + +=end comment +#============================================================================== + +use Test; + +subset S-type of Str where * ~~ / ^ <[ a .. z ]>+ $ /; + +my UInt constant $TEST-FLDS = 3; +my Bool constant $VERBOSE = True; + +#------------------------------------------------------------------------------ +BEGIN +#------------------------------------------------------------------------------ +{ + "\nChallenge 193, Task #2: Odd String (Raku)\n".put; +} + +#============================================================================== +multi sub MAIN +( + #| A list of 3+ same-length strings of lower case letters + + *@s where { .elems > 2 && .all ~~ S-type:D && .all.chars == @s[ 0 ].chars } +) +#============================================================================== +{ + "Input: \@s = (%s)\n".printf: @s.map( { qq["$_"] } ).join: ', '; + + my (Str $odd, Hash[Array[Str],Str] $diffs) = find-odd-string( @s ); + + "Output: $odd".put; + + print-diff-arrays( $diffs ) if $VERBOSE; +} + +#============================================================================== +multi sub MAIN() # Run the test suite +#============================================================================== +{ + run-tests(); +} + +#------------------------------------------------------------------------------ +sub find-odd-string +( + List:D[Str:D] $s +--> List:D[Str:D, Hash:D[List:D[Str:D]],Str:D] +) +#------------------------------------------------------------------------------ +{ + my Array[Str] %diff-arrays{Str} = get-all-diff-arrays( $s ); + + my Str $odd = 'None'; + my UInt $elems = $s.elems; + + given my UInt $diffs = %diff-arrays.keys.elems + { + when 1 + { + $odd ~= " (all $elems strings have the same difference array)"; + } + + when 2 + { + for %diff-arrays.values -> Array[Str] $list + { + $odd = '"' ~ $list[ 0 ] ~ '"', succeed if $list.elems == 1; + } + + proceed; + } + + default + { + $odd ~= " (the $elems strings have $diffs distinct difference " ~ + 'arrays)'; + } + } + + return $odd, %diff-arrays; +} + +#------------------------------------------------------------------------------ +sub get-all-diff-arrays( List:D[Str:D] $s --> Hash:D[List:D[Str:D]] ) +#------------------------------------------------------------------------------ +{ + my Array[Str] %diff-arrays{Str}; + + for @$s -> Str $str + { + my Int @diffs = get-one-diff-array( $str ); + my Str $gist = '[ ' ~ @diffs.join( ', ' ) ~ ' ]'; + + %diff-arrays{ $gist }.push: $str; + } + + return %diff-arrays; +} + +#------------------------------------------------------------------------------ +sub get-one-diff-array( Str:D $str --> List:D[Int:D] ) +#------------------------------------------------------------------------------ +{ + my Int @diffs; + my Str @chars = $str.split: '', :skip-empty; + + for 1 .. $str.chars - 1 -> UInt $i + { + @diffs.push: @chars[ $i ].ord - @chars[ $i - 1 ].ord; + } + + return @diffs; +} + +#------------------------------------------------------------------------------ +sub print-diff-arrays( Hash:D[List:D[Str:D],Str] $da2strs ) +#------------------------------------------------------------------------------ +{ + my Str %str2da; + + for %$da2strs.kv -> Str $key, Array[Str] $value # Reverse the hash + { + for @$value -> Str $str + { + %str2da{ $str } = $key; + } + } + + "\n Difference arrays:".put; + + for %str2da.keys.sort -> Str $str + { + qq[ "%s" => %s\n].printf: $str, %str2da{ $str }; + } +} + +#------------------------------------------------------------------------------ +sub run-tests() +#------------------------------------------------------------------------------ +{ + 'Running the test suite'.put; + + for test-data.lines -> Str $line + { + my Str ($test-name, $in, $expected) = + $line.split: / \, \s* /, $TEST-FLDS, :skip-empty; + + my Str @s = $in.split: / \s+ /, :skip-empty; + + my (Str $odd, Any) = find-odd-string( @s ); + + is $odd, $expected, $test-name; + } + + done-testing; +} + +#------------------------------------------------------------------------------ +sub error( Str:D $message ) +#------------------------------------------------------------------------------ +{ + "ERROR: $message".put; + + USAGE(); + + exit 0; +} + +#------------------------------------------------------------------------------ +sub USAGE() +#------------------------------------------------------------------------------ +{ + my Str $usage = $*USAGE; + + $usage ~~ s:g/ ($*PROGRAM-NAME) /raku $0/; + + $usage.put; +} + +#------------------------------------------------------------------------------ +sub test-data( --> Str:D ) +#------------------------------------------------------------------------------ +{ + return S:g/ \\ \n // with q:to/END/; + Example 1, adc wzy abc, abc + Example 2, aaa bob ccc ddd, bob + All same, adc wzy vyx bed, \ + None (all 4 strings have the same difference array) + Two odd, mor jlo abc def, \ + None (the 4 strings have 2 distinct difference arrays) + All odd, abc acd ade aef afg, \ + None (the 5 strings have 5 distinct difference arrays) + Odd plus, adc wzy abc jop kpq, \ + None (the 5 strings have 3 distinct difference arrays) + END +} + +############################################################################### |
