aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohammad Sajid Anwar <Mohammad.Anwar@yahoo.com>2023-12-03 12:55:18 +0000
committerGitHub <noreply@github.com>2023-12-03 12:55:18 +0000
commit42f3795a1b6f04418786c0837278b58bc910511b (patch)
tree01be59866a55822a43c01648b34f455e41454927
parent9b0b58691db7a2821f8d196138d59f57c2b0aee3 (diff)
parent8e669183c422cb5361a61c07531f32dcfaf47df2 (diff)
downloadperlweeklychallenge-club-42f3795a1b6f04418786c0837278b58bc910511b.tar.gz
perlweeklychallenge-club-42f3795a1b6f04418786c0837278b58bc910511b.tar.bz2
perlweeklychallenge-club-42f3795a1b6f04418786c0837278b58bc910511b.zip
Merge pull request #9175 from PerlMonk-Athanasius/branch-for-challenge-245
Perl & Raku solutions to Tasks 1 & 2 for Week 245
-rw-r--r--challenge-245/athanasius/perl/ch-1.pl197
-rw-r--r--challenge-245/athanasius/perl/ch-2.pl195
-rw-r--r--challenge-245/athanasius/raku/ch-1.raku182
-rw-r--r--challenge-245/athanasius/raku/ch-2.raku190
4 files changed, 764 insertions, 0 deletions
diff --git a/challenge-245/athanasius/perl/ch-1.pl b/challenge-245/athanasius/perl/ch-1.pl
new file mode 100644
index 0000000000..5cad0c9ab4
--- /dev/null
+++ b/challenge-245/athanasius/perl/ch-1.pl
@@ -0,0 +1,197 @@
+#!perl
+
+################################################################################
+=comment
+
+Perl Weekly Challenge 245
+=========================
+
+TASK #1
+-------
+*Sort Language*
+
+Submitted by: Mohammad S Anwar
+
+You are given two array of languages and its popularity.
+
+Write a script to sort the language based on popularity.
+
+Example 1
+
+ Input: @lang = ('perl', 'c', 'python')
+ @popularity = (2, 1, 3)
+ Output: ('c', 'perl', 'python')
+
+Example 2
+
+ Input: @lang = ('c++', 'haskell', 'java')
+ @popularity = (1, 3, 2)
+ Output: ('c++', 'java', 'haskell')
+
+=cut
+################################################################################
+
+#--------------------------------------#
+# Copyright © 2023 PerlMonk Athanasius #
+#--------------------------------------#
+
+#===============================================================================
+=comment
+
+Interface
+---------
+1. If no command-line arguments are given, the test suite is run. Otherwise:
+2. Language names are entered as a single, whitespace-separated string named
+ "lang", for example: --lang="c++ haskell java"
+3. Popularity ratings are entered as a list of unsigned integers. The number of
+ popularity ratings must equal the number of language names. Duplicate popu-
+ larity ratings are allowed: languages with identical popularities are sorted
+ in alphabetical order.
+
+=cut
+#===============================================================================
+
+use v5.32.1; # Enables strictures
+use warnings;
+use Const::Fast;
+use Getopt::Long;
+use List::MoreUtils qw( mesh );
+use Regexp::Common qw( number );
+use Test::More;
+
+const my $USAGE =>
+"Usage:
+ perl $0 [--lang=<Str>] [<popularity> ...]
+ perl $0
+
+ --lang=<Str> A whitespace-separated list of language names
+ [<popularity> ...] A list of popularity ratings for the given languages
+";
+
+#-------------------------------------------------------------------------------
+BEGIN
+#-------------------------------------------------------------------------------
+{
+ $| = 1;
+ print "\nChallenge 245, Task #1: Sort Language (Perl)\n\n";
+}
+
+#===============================================================================
+MAIN:
+#===============================================================================
+{
+ if (scalar @ARGV == 0)
+ {
+ run_tests();
+ }
+ else
+ {
+ my ($languages, $popularity) = parse_command_line();
+
+ printf "Input: \@languages = (%s)\n", format_langs( $languages );
+ printf " \@popularity = (%s)\n", join ', ', @$popularity;
+
+ my $sorted = sort_languages( $languages, $popularity );
+
+ printf "Output: (%s)\n", format_langs( $sorted );
+ }
+}
+
+#-------------------------------------------------------------------------------
+sub sort_languages
+#-------------------------------------------------------------------------------
+{
+ my ($languages, $popularity) = @_;
+
+ my %dict = mesh @$languages, @$popularity;
+ my @sorted = sort
+ { # Sort (ascending) by:
+ $dict{ $a } <=> $dict{ $b } || # 1. popularity; then
+ $a cmp $b # 2. alphabetical order
+
+ } @$languages;
+
+ return \@sorted;
+}
+
+#-------------------------------------------------------------------------------
+sub parse_command_line
+#-------------------------------------------------------------------------------
+{
+ my $lang_str;
+
+ GetOptions( 'lang=s' => \$lang_str )
+ or error( 'Error in command line arguments' );
+
+ defined $lang_str or error( 'No language names given' );
+
+ my @languages = split / \s+ /x, $lang_str;
+ my @popularity = @ARGV;
+
+ for (@popularity)
+ {
+ / ^ $RE{num}{int} $ /x
+ or error( qq["$_" is not a valid integer] );
+
+ $_ >= 0 or error( qq["$_" is negative] );
+ }
+
+ scalar @languages == scalar @popularity
+ or error( 'The input lists have different sizes' );
+
+ return (\@languages, \@popularity);
+}
+
+#-------------------------------------------------------------------------------
+sub format_langs
+#-------------------------------------------------------------------------------
+{
+ my ($languages) = @_;
+
+ return join ', ', map { "'$_'" } @$languages;
+}
+
+#-------------------------------------------------------------------------------
+sub run_tests
+#-------------------------------------------------------------------------------
+{
+ print "Running the test suite\n";
+
+ while (my $line = <DATA>)
+ {
+ chomp $line;
+
+ my ($test_name, $languages_str, $popularity_str, $expected_str) =
+ split / \| /x, $line;
+
+ for ($test_name, $languages_str, $popularity_str, $expected_str)
+ {
+ s/ ^ \s+ //x;
+ s/ \s+ $ //x;
+ }
+
+ my @languages = split / \s+ /x, $languages_str;
+ my @popularity = split / \s+ /x, $popularity_str;
+ my @expected = split / \s+ /x, $expected_str;
+ my $sorted = sort_languages( \@languages, \@popularity );
+
+ is_deeply $sorted, \@expected, $test_name;
+ }
+
+ done_testing;
+}
+
+#-------------------------------------------------------------------------------
+sub error
+#-------------------------------------------------------------------------------
+{
+ my ($message) = @_;
+
+ die "ERROR: $message\n$USAGE";
+}
+
+################################################################################
+
+__DATA__
+Example 1|perl c python |2 1 3|c perl python
+Example 2|c++ haskell java|1 3 2|c++ java haskell
diff --git a/challenge-245/athanasius/perl/ch-2.pl b/challenge-245/athanasius/perl/ch-2.pl
new file mode 100644
index 0000000000..c94c2be714
--- /dev/null
+++ b/challenge-245/athanasius/perl/ch-2.pl
@@ -0,0 +1,195 @@
+#!perl
+
+################################################################################
+=comment
+
+Perl Weekly Challenge 245
+=========================
+
+TASK #2
+-------
+*Largest of Three*
+
+Submitted by: Mohammad S Anwar
+
+You are given an array of integers >= 0.
+
+Write a script to return the largest number formed by concatenating some of the
+given integers in any order which is also multiple of 3. Return -1 if none
+found.
+
+Example 1
+
+ Input: @ints = (8, 1, 9)
+ Output: 981
+
+ 981 % 3 == 0
+
+Example 2
+
+ Input: @ints = (8, 6, 7, 1, 0)
+ Output: 8760
+
+Example 3
+
+ Input: @ints = (1)
+ Output: -1
+
+=cut
+################################################################################
+
+#--------------------------------------#
+# Copyright © 2023 PerlMonk Athanasius #
+#--------------------------------------#
+
+#===============================================================================
+=comment
+
+Interface
+---------
+If no command-line arguments are given, the test suite is run.
+
+Assumption
+----------
+Duplicates are allowed in the input list.
+
+Observation
+-----------
+Any natural number represented in decimal (aka denary) notation is a multiple of
+3 if and only if the recursive sum of its digits is also a multiple of 3.
+
+ For example, 819 -> 8 + 1 + 9 = 18 -> 1 + 8 = 9, and 9 is a multiple of 3,
+ so 819 has been shown to be a multiple of 3.
+
+From this it follows that, for any given subset of the input integers, concaten-
+ating and testing for multiplicity-of-3 will give the same result regardless of
+the order in which the integers are concatenated. The solution below takes ad-
+vantage of this fact by testing only the largest number which can be formed by
+concatenating each possible subset. Since candidate solutions are evaluated in
+order from largest to smallest, the first successful candidate is immediately
+returned as the best solution.
+
+=cut
+#===============================================================================
+
+use v5.32.1; # Enables strictures
+use warnings;
+use Algorithm::Combinatorics qw( combinations );
+use Const::Fast;
+use Regexp::Common qw( number );
+use Test::More;
+
+const my $USAGE =>
+"Usage:
+ perl $0 [<ints> ...]
+ perl $0
+
+ [<ints> ...] A list of integers >= 0\n";
+
+#-------------------------------------------------------------------------------
+BEGIN
+#-------------------------------------------------------------------------------
+{
+ $| = 1;
+ print "\nChallenge 245, Task #2: Largest of Three (Perl)\n\n";
+}
+
+#===============================================================================
+MAIN:
+#===============================================================================
+{
+ if (scalar @ARGV == 0)
+ {
+ run_tests();
+ }
+ else
+ {
+ my @ints = @ARGV;
+
+ for (@ints)
+ {
+ / ^ $RE{num}{int} $ /x or error( qq["$_" is not a valid integer] );
+ $_ >= 0 or error( qq["$_" is negative] );
+ }
+
+ printf "Input: \@ints = (%s)\n", join ', ', @ints;
+
+ my $lot = largest_of_three( \@ints );
+
+ print "Output: $lot\n";
+ }
+}
+
+#-------------------------------------------------------------------------------
+sub largest_of_three
+#-------------------------------------------------------------------------------
+{
+ my ($ints) = @_;
+
+ # Note the use of the *stringwise* comparison operator leg instead of <=>
+ # here: this effectively sorts by digits, most- to least-significant,
+ # rather than by total numerical value
+
+ my @sorted = sort { $b cmp $a } @$ints;
+
+ for my $digits (reverse (1 .. scalar @sorted))
+ {
+ my $iter = combinations( \@sorted, $digits );
+
+ while (my $comb = $iter->next)
+ {
+ my $candidate = join '', @$comb;
+
+ return $candidate if $candidate % 3 == 0;
+ }
+ }
+
+ return -1;
+}
+
+#-------------------------------------------------------------------------------
+sub run_tests
+#-------------------------------------------------------------------------------
+{
+ print "Running the test suite\n";
+
+ while (my $line = <DATA>)
+ {
+ chomp $line;
+
+ my ($test_name, $ints_str, $expected) = split / \| /x, $line;
+
+ for ($test_name, $ints_str, $expected)
+ {
+ s/ ^ \s+ //x;
+ s/ \s+ $ //x;
+ }
+
+ my @ints = split / \s+ /x, $ints_str;
+ my $lot = largest_of_three( \@ints );
+
+ is $lot, $expected, $test_name;
+ }
+
+ done_testing;
+}
+
+#-------------------------------------------------------------------------------
+sub error
+#-------------------------------------------------------------------------------
+{
+ my ($message) = @_;
+
+ die "ERROR: $message\n$USAGE";
+}
+
+################################################################################
+
+__DATA__
+Example 1| 8 1 9 | 981
+Example 2| 8 6 7 1 0| 8760
+Example 3| 1 | -1
+Multiples| 1 1 4 2 | 411
+Small | 8 2 9 | 9
+Tens | 81 9 10 | 981
+Hundreds |198 30 500 |30198
diff --git a/challenge-245/athanasius/raku/ch-1.raku b/challenge-245/athanasius/raku/ch-1.raku
new file mode 100644
index 0000000000..9668f4efd5
--- /dev/null
+++ b/challenge-245/athanasius/raku/ch-1.raku
@@ -0,0 +1,182 @@
+use v6d;
+
+################################################################################
+=begin comment
+
+Perl Weekly Challenge 245
+=========================
+
+TASK #1
+-------
+*Sort Language*
+
+Submitted by: Mohammad S Anwar
+
+You are given two array of languages and its popularity.
+
+Write a script to sort the language based on popularity.
+
+Example 1
+
+ Input: @lang = ('perl', 'c', 'python')
+ @popularity = (2, 1, 3)
+ Output: ('c', 'perl', 'python')
+
+Example 2
+
+ Input: @lang = ('c++', 'haskell', 'java')
+ @popularity = (1, 3, 2)
+ Output: ('c++', 'java', 'haskell')
+
+=end comment
+################################################################################
+
+#--------------------------------------#
+# Copyright © 2023 PerlMonk Athanasius #
+#--------------------------------------#
+
+#===============================================================================
+=begin comment
+
+Interface
+---------
+1. If no command-line arguments are given, the test suite is run. Otherwise:
+2. Language names are entered as a single, whitespace-separated string named
+ "lang", for example: --lang="c++ haskell java"
+3. Popularity ratings are entered as a list of unsigned integers. The number of
+ popularity ratings must equal the number of language names. Duplicate popu-
+ larity ratings are allowed: languages with identical popularities are sorted
+ in alphabetical order.
+
+=end comment
+#===============================================================================
+
+use Test;
+
+#-------------------------------------------------------------------------------
+BEGIN
+#-------------------------------------------------------------------------------
+{
+ "\nChallenge 245, Task #1: Sort Language (Raku)\n".put;
+}
+
+#===============================================================================
+multi sub MAIN
+(
+ #| A whitespace-separated list of language names
+
+ Str :$lang,
+
+ #| A list of popularity ratings for the given languages
+
+ *@popularity where { .elems > 0 && .all ~~ UInt:D }
+)
+#===============================================================================
+{
+ my Str @languages = $lang.split: / \s+ /, :skip-empty;
+
+ @languages.elems == @popularity.elems
+ or error( 'The input lists have different sizes' );
+
+ "Input: \@languages = (%s)\n".printf: format-langs( @languages );
+ " \@popularity = (%s)\n".printf: @popularity.join: ', ';
+
+ my Str @sorted = sort-languages( @languages, @popularity );
+
+ "Output: (%s)\n"\.printf: format-langs( @sorted );
+}
+
+#===============================================================================
+multi sub MAIN() # No input: run the test suite
+#===============================================================================
+{
+ run-tests();
+}
+
+#-------------------------------------------------------------------------------
+sub sort-languages
+(
+ List:D[Str:D] $languages,
+ List:D[UInt:D] $popularity where { .elems == $languages.elems }
+--> List:D[Str:D]
+)
+#-------------------------------------------------------------------------------
+{
+ my UInt %dict{Str} = @$languages Z=> $popularity.map: { .Int };
+ my Str @sorted = $languages.sort:
+ { # Sort (ascending) by:
+ %dict{ $^a } <=> %dict{ $^b } || # 1. popularity; then
+ $^a leg $^b # 2. alphabetical order
+ };
+
+ return @sorted;
+}
+
+#-------------------------------------------------------------------------------
+sub format-langs( List:D[Str:D] $languages --> Str:D )
+#-------------------------------------------------------------------------------
+{
+ return $languages.map( { "'$_'" } ).join: ', ';
+}
+
+#-------------------------------------------------------------------------------
+sub run-tests()
+#-------------------------------------------------------------------------------
+{
+ 'Running the test suite'.put;
+
+ for test-data.lines -> Str $line
+ {
+ my Str ($test-name, $languages-str, $popularity-str, $expected-str) =
+ $line.split: / \| /;
+
+ for $test-name, $languages-str, $popularity-str, $expected-str
+ {
+ s/ ^ \s+ //;
+ s/ \s+ $ //;
+ }
+
+ my Str @languages = $languages-str\.split( / \s+ / );
+ my UInt @popularity = $popularity-str.split( / \s+ / ).map: { .Int };
+ my Str @expected = $expected-str\ .split( / \s+ / );
+ my Str @sorted = sort-languages( @languages, @popularity );
+
+ is-deeply @sorted, @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 q:to/END/;
+ Example 1|perl c python |2 1 3|c perl python
+ Example 2|c++ haskell java|1 3 2|c++ java haskell
+ END
+}
+
+################################################################################
diff --git a/challenge-245/athanasius/raku/ch-2.raku b/challenge-245/athanasius/raku/ch-2.raku
new file mode 100644
index 0000000000..3e27ccbf30
--- /dev/null
+++ b/challenge-245/athanasius/raku/ch-2.raku
@@ -0,0 +1,190 @@
+use v6d;
+
+################################################################################
+=begin comment
+
+Perl Weekly Challenge 245
+=========================
+
+TASK #2
+-------
+*Largest of Three*
+
+Submitted by: Mohammad S Anwar
+
+You are given an array of integers >= 0.
+
+Write a script to return the largest number formed by concatenating some of the
+given integers in any order which is also multiple of 3. Return -1 if none
+found.
+
+Example 1
+
+ Input: @ints = (8, 1, 9)
+ Output: 981
+
+ 981 % 3 == 0
+
+Example 2
+
+ Input: @ints = (8, 6, 7, 1, 0)
+ Output: 8760
+
+Example 3
+
+ Input: @ints = (1)
+ Output: -1
+
+=end comment
+################################################################################
+
+#--------------------------------------#
+# Copyright © 2023 PerlMonk Athanasius #
+#--------------------------------------#
+
+#===============================================================================
+=begin comment
+
+Interface
+---------
+If no command-line arguments are given, the test suite is run.
+
+Assumption
+----------
+Duplicates are allowed in the input list.
+
+Observation
+-----------
+Any natural number represented in decimal (aka denary) notation is a multiple of
+3 if and only if the recursive sum of its digits is also a multiple of 3.
+
+ For example, 819 -> 8 + 1 + 9 = 18 -> 1 + 8 = 9, and 9 is a multiple of 3,
+ so 819 has been shown to be a multiple of 3.
+
+From this it follows that, for any given subset of the input integers, concaten-
+ating and testing for multiplicity-of-3 will give the same result regardless of
+the order in which the integers are concatenated. The solution below takes ad-
+vantage of this fact by testing only the largest number which can be formed by
+concatenating each possible subset. Since candidate solutions are evaluated in
+order from largest to smallest, the first successful candidate is immediately
+returned as the best solution.
+
+=end comment
+#===============================================================================
+
+use Test;
+
+#-------------------------------------------------------------------------------
+BEGIN
+#-------------------------------------------------------------------------------
+{
+ "\nChallenge 245, Task #2: Largest of Three (Raku)\n".put;
+}
+
+#===============================================================================
+multi sub MAIN
+(
+ *@ints where { .elems > 0 && .all ~~ UInt:D } #= A list of integers >= 0
+)
+#===============================================================================
+{
+ "Input: \@ints = (%s)\n".printf: @ints.join: ', ';
+
+ my Int $lot = largest-of-three( @ints );
+
+ "Output: $lot".put;
+}
+
+#===============================================================================
+multi sub MAIN() # No input: run the test suite
+#===============================================================================
+{
+ run-tests();
+}
+
+#-------------------------------------------------------------------------------
+sub largest-of-three( List:D[UInt:D] $ints --> Int:D )
+#-------------------------------------------------------------------------------
+{
+ # Note the use of the *stringwise* comparison operator leg instead of <=>
+ # here: this effectively sorts by digits, most- to least-significant,
+ # rather than by total numerical value
+
+ my UInt @sorted = $ints.sort: { $^b leg $^a };
+
+ for @sorted.elems ... 1 -> UInt $digits
+ {
+ for @sorted.combinations( $digits )
+ {
+ my UInt $candidate = .join( '' ).Int;
+
+ return $candidate if $candidate %% 3;
+ }
+ }
+
+ return -1;
+}
+
+#-------------------------------------------------------------------------------
+sub run-tests()
+#-------------------------------------------------------------------------------
+{
+ 'Running the test suite'.put;
+
+ for test-data.lines -> Str $line
+ {
+ my Str ($test-name, $ints-str, $expected) = $line.split: / \| /;
+
+ for $test-name, $ints-str, $expected
+ {
+ s/ ^ \s+ //;
+ s/ \s+ $ //;
+ }
+
+ my Int @ints = $ints-str.split( / \s+ / ).map: { .Int };
+ my Int $lot = largest-of-three( @ints );
+
+ is $lot, $expected.Int, $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 q:to/END/;
+ Example 1| 8 1 9 | 981
+ Example 2| 8 6 7 1 0| 8760
+ Example 3| 1 | -1
+ Multiples| 1 1 4 2 | 411
+ Small | 8 2 9 | 9
+ Tens | 81 9 10 | 981
+ Hundreds |198 30 500 |30198
+ END
+}
+
+################################################################################