aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPerlMonk-Athanasius <PerlMonk.Athanasius@gmail.com>2023-01-08 22:02:54 +1000
committerPerlMonk-Athanasius <PerlMonk.Athanasius@gmail.com>2023-01-08 22:02:54 +1000
commit18f15abfd63dd65c6d79f446c0381856df7e1d44 (patch)
tree466a24128a061bf2569258ecd0abea06f1b2f3d5
parent30bc90811147ec3a3ccfefa2dff445fee9225d9d (diff)
downloadperlweeklychallenge-club-18f15abfd63dd65c6d79f446c0381856df7e1d44.tar.gz
perlweeklychallenge-club-18f15abfd63dd65c6d79f446c0381856df7e1d44.tar.bz2
perlweeklychallenge-club-18f15abfd63dd65c6d79f446c0381856df7e1d44.zip
Perl & Raku solutions to Tasks 1 & 2 for Week 198
-rw-r--r--challenge-198/athanasius/perl/ch-1.pl174
-rw-r--r--challenge-198/athanasius/perl/ch-2.pl157
-rw-r--r--challenge-198/athanasius/raku/ch-1.raku196
-rw-r--r--challenge-198/athanasius/raku/ch-2.raku188
4 files changed, 715 insertions, 0 deletions
diff --git a/challenge-198/athanasius/perl/ch-1.pl b/challenge-198/athanasius/perl/ch-1.pl
new file mode 100644
index 0000000000..8fc6f57582
--- /dev/null
+++ b/challenge-198/athanasius/perl/ch-1.pl
@@ -0,0 +1,174 @@
+#!perl
+
+###############################################################################
+=comment
+
+Perl Weekly Challenge 198
+=========================
+
+TASK #1
+-------
+*Max Gap*
+
+Submitted by: Mohammad S Anwar
+
+You are given a list of integers, @list.
+
+Write a script to find the total pairs in the sorted list where 2 consecutive
+elements has the max gap. If the list contains less then 2 elements then return
+0.
+
+Example 1
+
+ Input: @list = (2,5,8,1)
+ Output: 2
+
+ Since the sorted list (1,2,5,8) has 2 such pairs (2,5) and (5,8)
+
+Example 2
+
+ Input: @list = (3)
+ Output: 0
+
+=cut
+###############################################################################
+
+#--------------------------------------#
+# Copyright © 2023 PerlMonk Athanasius #
+#--------------------------------------#
+
+#==============================================================================
+=comment
+
+Interface
+---------
+1. If no command-line arguments are given, the test suite is run.
+2. If $VERBOSE is set to a true value, an explanation like that in Example 1 is
+ added to the solution.
+
+=cut
+#==============================================================================
+
+use strict;
+use warnings;
+use Const::Fast;
+use Regexp::Common qw( number );
+use Test::More;
+
+const my $TEST_FIELDS => 3;
+const my $VERBOSE => 1;
+const my $USAGE =>
+"Usage:
+ perl $0 [<list> ...]
+ perl $0
+
+ [<list> ...] A list of 1 or more integers\n";
+
+#------------------------------------------------------------------------------
+BEGIN
+#------------------------------------------------------------------------------
+{
+ $| = 1;
+ print "\nChallenge 198, Task #1: Max Gap (Perl)\n\n";
+}
+
+#==============================================================================
+MAIN:
+#==============================================================================
+{
+ if (scalar @ARGV == 0)
+ {
+ run_tests();
+ }
+ else
+ {
+ my @list = @ARGV;
+
+ for (@list)
+ {
+ / ^ $RE{num}{int} $ /x
+ or die qq[ERROR: "$_" is not a valid integer\n$USAGE];
+ }
+
+ printf "Input: \@list = (%s)\n", join ', ', @list;
+
+ my ($max_pairs, $max_gap, $pairs) = max_gap( @list );
+
+ print "Output: $max_pairs\n";
+
+ if ($VERBOSE && scalar @list > 1)
+ {
+ printf "\nSince the sorted list (%s) has %d pair%s with the " .
+ "maximum gap of %d:\n%s\n",
+ join( ',', sort { $a <=> $b } @list ),
+ $max_pairs,
+ ($max_pairs == 1 ? '' : 's'),
+ $max_gap,
+ join( ', ', map { '(' . join( ',', @$_ ) . ')' } @$pairs );
+ }
+ }
+}
+
+#------------------------------------------------------------------------------
+sub max_gap
+#------------------------------------------------------------------------------
+{
+ my @list = @_;
+ my @sorted = sort { $a <=> $b } @list;
+ my ($max_gap, $max_pairs, @pairs) = (-1, 0, ());
+
+ for my $i (0 .. $#sorted - 1)
+ {
+ my $gap = $sorted[ $i + 1 ] - $sorted[ $i ];
+
+ if ($gap > $max_gap)
+ {
+ $max_gap = $gap;
+ $max_pairs = 1;
+ @pairs = [ @sorted[ $i, $i + 1 ] ];
+ }
+ elsif ($gap == $max_gap)
+ {
+ ++$max_pairs;
+ push @pairs, [ @sorted[ $i, $i + 1 ] ];
+ }
+ }
+
+ return ($max_pairs, $max_gap, \@pairs);
+}
+
+#------------------------------------------------------------------------------
+sub run_tests
+#------------------------------------------------------------------------------
+{
+ print "Running the test suite\n";
+
+ while (my $line = <DATA>)
+ {
+ chomp $line;
+
+ my ($test_name, $input, $expected) = split /\|/, $line, $TEST_FIELDS;
+
+ $input =~ s/ ^ \s* (.+?) \s* $ /$1/x; # Trim whitespace
+ $expected =~ s/ ^ \s* (.+?) \s* $ /$1/x;
+ $expected =~ s/ \s+ / /gx;
+
+ my @list = split / , \s+ /x, $input;
+
+ my ($max_pairs, undef, undef) = max_gap( @list );
+
+ my $got = join ', ', $max_pairs;
+
+ is $got, $expected, $test_name;
+ }
+
+ done_testing;
+}
+
+###############################################################################
+
+__DATA__
+Example 1| 2, 5, 8, 1 |2
+Example 2| 3 |0
+Negatives|-5, -1, -3 |2
+Mixed |-3, 4, 2, -1, 1|3
diff --git a/challenge-198/athanasius/perl/ch-2.pl b/challenge-198/athanasius/perl/ch-2.pl
new file mode 100644
index 0000000000..06e53e858e
--- /dev/null
+++ b/challenge-198/athanasius/perl/ch-2.pl
@@ -0,0 +1,157 @@
+#!perl
+
+###############################################################################
+=comment
+
+Perl Weekly Challenge 198
+=========================
+
+TASK #2
+-------
+*Prime Count*
+
+Submitted by: Mohammad S Anwar
+
+You are given an integer $n > 0.
+
+Write a script to print the count of primes less than $n.
+
+Example 1
+
+ Input: $n = 10
+ Output: 4 as in there are 4 primes less than 10 are 2, 3, 5, 7.
+
+Example 2
+
+ Input: $n = 15
+ Output: 6
+
+Example 3
+
+ Input: $n = 1
+ Output: 0
+
+Example 4
+
+ Input: $n = 25
+ Output: 9
+
+=cut
+###############################################################################
+
+#--------------------------------------#
+# Copyright © 2023 PerlMonk Athanasius #
+#--------------------------------------#
+
+#==============================================================================
+=comment
+
+Interface
+---------
+If no command-line argument is given, the test suite is run.
+
+=cut
+#==============================================================================
+
+use strict;
+use warnings;
+use Const::Fast;
+use ntheory qw( prime_count );
+use Regexp::Common qw( number );
+use Test::More;
+
+const my $TEST_FIELDS => 3;
+const my $USAGE =>
+"Usage:
+ perl $0 [<list> ...]
+ perl $0
+
+ [<list> ...] An integer greater than zero\n";
+
+#------------------------------------------------------------------------------
+BEGIN
+#------------------------------------------------------------------------------
+{
+ $| = 1;
+ print "\nChallenge 198, Task #2: Prime Count (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["$_" is not a valid integer] );
+
+ $n > 0 or error( "$n is not greater than zero" );
+
+ print "Input: \$n = $n\n";
+ printf "Output: %d\n", count_primes( $n );
+ }
+ else
+ {
+ error( "Expected 1 or 0 command line arguments, found $args" );
+ }
+}
+
+#------------------------------------------------------------------------------
+sub count_primes
+#------------------------------------------------------------------------------
+{
+ my ($n) = @_;
+
+ # Note: The count returned by Math::Prime::Util::prime_count( $x ) is
+ # *inclusive* of $x
+
+ return prime_count( $n - 1 );
+}
+
+#------------------------------------------------------------------------------
+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 / \| /x, $line, $TEST_FIELDS;
+
+ s/ ^ \s* (.+?) \s* $ /$1/x # Trim whitespace
+ for $test_name, $n, $expected;
+
+ is count_primes( $n ), $expected, $test_name;
+ }
+
+ done_testing;
+}
+
+###############################################################################
+
+__DATA__
+Example 1| 10| 4
+Example 2| 15| 6
+Example 3| 1| 0
+Example 4| 25| 9
+Large n | 1000000| 78498
+Huge n |1234567890|62106578
diff --git a/challenge-198/athanasius/raku/ch-1.raku b/challenge-198/athanasius/raku/ch-1.raku
new file mode 100644
index 0000000000..661569d567
--- /dev/null
+++ b/challenge-198/athanasius/raku/ch-1.raku
@@ -0,0 +1,196 @@
+use v6d;
+
+###############################################################################
+=begin comment
+
+Perl Weekly Challenge 198
+=========================
+
+TASK #1
+-------
+*Max Gap*
+
+Submitted by: Mohammad S Anwar
+
+You are given a list of integers, @list.
+
+Write a script to find the total pairs in the sorted list where 2 consecutive
+elements has the max gap. If the list contains less then 2 elements then return
+0.
+
+Example 1
+
+ Input: @list = (2,5,8,1)
+ Output: 2
+
+ Since the sorted list (1,2,5,8) has 2 such pairs (2,5) and (5,8)
+
+Example 2
+
+ Input: @list = (3)
+ Output: 0
+
+=end comment
+###############################################################################
+
+#--------------------------------------#
+# Copyright © 2023 PerlMonk Athanasius #
+#--------------------------------------#
+
+#==============================================================================
+=begin comment
+
+Interface
+---------
+1. If no command-line arguments are given, the test suite is run.
+2. If the first argument is negative, it must be preceded by "--" to distin-
+ guish it from a command-line flag.
+3. If $VERBOSE is set to True, an explanation like that in Example 1 is added
+ to the solution.
+
+=end comment
+#==============================================================================
+
+use Test;
+
+my UInt constant $TEST-FIELDS = 3;
+my Bool constant $VERBOSE = True;
+
+#------------------------------------------------------------------------------
+BEGIN
+#------------------------------------------------------------------------------
+{
+ "\nChallenge 198, Task #1: Max Gap (Raku)\n".put;
+}
+
+#==============================================================================
+multi sub MAIN
+(
+ #| A list of 1 or more integers
+
+ *@list where { .elems >= 1 && .all ~~ Int:D }
+)
+#==============================================================================
+{
+ "Input: \@list = (%s)\n".printf: @list.join: ', ';
+
+ my (UInt $max-pairs, Int $max-gap, Array[Array[Int]] $pairs) =
+ max-gap( @list );
+
+ "Output: $max-pairs".put;
+
+ if $VERBOSE && @list.elems > 1
+ {
+ ("\nSince the sorted list (%s) has %d pair%s with the maximum gap " ~
+ "of %d:\n%s\n").printf:
+ @list.sort.join( ',' ),
+ $max-pairs,
+ ($max-pairs == 1 ?? '' !! 's'),
+ $max-gap,
+ @$pairs.map( { '(' ~ @$_.join( ',' ) ~ ')' } ).join: ', ';
+ }
+}
+
+#==============================================================================
+multi sub MAIN() # No input: run the test suite
+#==============================================================================
+{
+ run-tests();
+}
+
+#------------------------------------------------------------------------------
+sub max-gap
+(
+ List:D[Int:D] $list
+--> List:D[UInt:D, Int:D, List:D[List:D[Int:D]]]
+)
+#------------------------------------------------------------------------------
+{
+ my Int @sorted = $list.sort;
+ my Int $max-gap = -1;
+ my UInt $max-pairs = 0;
+ my Array[Int] @pairs;
+
+ for 0 .. @sorted.end - 1 -> UInt $i
+ {
+ my UInt $gap = @sorted[ $i + 1 ] - @sorted[ $i ];
+
+ if $gap > $max-gap
+ {
+ $max-gap = $gap;
+ $max-pairs = 1;
+ @pairs = Empty;
+ @pairs.push: Array[Int].new: @sorted[ $i, $i + 1 ];
+ }
+ elsif $gap == $max-gap
+ {
+ ++$max-pairs;
+ @pairs.push: Array[Int].new: @sorted[ $i, $i + 1 ];
+ }
+ }
+
+ return $max-pairs, $max-gap, @pairs;
+}
+
+#------------------------------------------------------------------------------
+sub run-tests()
+#------------------------------------------------------------------------------
+{
+ 'Running the test suite'.put;
+
+ for test-data.lines -> Str $line
+ {
+ my Str ($test-name, $input, $expected) =
+ $line.split: / \| /, $TEST-FIELDS;
+
+ $input ~~ s/ ^ \s* (.+?) \s* $ /$0/; # Trim whitespace
+ $expected ~~ s/ ^ \s* (.+?) \s* $ /$0/;
+ $expected ~~ s:g/ \s+ / /;
+
+ my Int @list = $input.split( / \, \s* / ).map: { .Int };
+
+ my (UInt $max-pairs, $, $) = max-gap( @list );
+
+ my Str $got = $max-pairs.join: ', ';
+
+ is $got, $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| 2, 5, 8, 1 |2
+ Example 2| 3 |0
+ Negatives|-5, -1, -3 |2
+ Mixed |-3, 4, 2, -1, 1|3
+ END
+}
+
+###############################################################################
diff --git a/challenge-198/athanasius/raku/ch-2.raku b/challenge-198/athanasius/raku/ch-2.raku
new file mode 100644
index 0000000000..3d6f4f5d02
--- /dev/null
+++ b/challenge-198/athanasius/raku/ch-2.raku
@@ -0,0 +1,188 @@
+use v6d;
+
+###############################################################################
+=begin comment
+
+Perl Weekly Challenge 198
+=========================
+
+TASK #2
+-------
+*Prime Count*
+
+Submitted by: Mohammad S Anwar
+
+You are given an integer $n > 0.
+
+Write a script to print the count of primes less than $n.
+
+Example 1
+
+ Input: $n = 10
+ Output: 4 as in there are 4 primes less than 10 are 2, 3, 5, 7.
+
+Example 2
+
+ Input: $n = 15
+ Output: 6
+
+Example 3
+
+ Input: $n = 1
+ Output: 0
+
+Example 4
+
+ Input: $n = 25
+ Output: 9
+
+=end comment
+###############################################################################
+
+#--------------------------------------#
+# Copyright © 2023 PerlMonk Athanasius #
+#--------------------------------------#
+
+#==============================================================================
+=begin comment
+
+Interface
+---------
+If no command-line arguments are given, the test suite is run.
+
+Algorithm
+---------
+Neither Inline::Perl5 (for Math::Prime::Util/ntheory) nor Math::Primesieve will
+(currently) install on my Rakudo platform. I have therefore implemented a Sieve
+of Eratosthenes [1] to generate primes up to the given n.
+
+This performs well for small values of n, but is quite slow for larger values:
+e.g., for n = one million, the sieve takes about 24 seconds. By comparison, the
+ntheory::prime_count() function takes about 0.005 seconds for the same n.
+
+Reference
+---------
+[1] "Sieve of Eratosthenes", Wikipedia,
+ https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
+
+=end comment
+#==============================================================================
+
+use Test;
+
+my UInt constant $TEST-FIELDS = 3;
+
+#------------------------------------------------------------------------------
+BEGIN
+#------------------------------------------------------------------------------
+{
+ "\nChallenge 198, Task #2: Prime Count (Raku)\n".put;
+}
+
+#==============================================================================
+multi sub MAIN
+(
+ UInt:D $n where { $n > 0 } #= An integer greater than zero
+)
+#==============================================================================
+{
+ "Input: \$n = $n".put;
+
+ "Output: %d\n".printf: count-primes( $n );
+}
+
+#==============================================================================
+multi sub MAIN() # Run the test suite
+#==============================================================================
+{
+ run-tests();
+}
+
+#------------------------------------------------------------------------------
+sub count-primes( UInt:D $n where { $n > 0 } --> UInt:D )
+#------------------------------------------------------------------------------
+{
+ my UInt $count = 0;
+ my Bool @sieve = |(False xx 2), |(True xx ($n - 2));
+ my UInt $sqrt-n = $n.sqrt.floor;
+
+ for 2 .. $sqrt-n -> UInt $i
+ {
+ if @sieve[ $i ]
+ {
+ ++$count;
+
+ for 0 .. * -> UInt $j
+ {
+ my UInt $k = $i² + $j * $i;
+
+ last if $k >= $n;
+
+ @sieve[ $k ] = False;
+ }
+ }
+ }
+
+ for $sqrt-n + 1 .. $n - 1 -> UInt $m
+ {
+ ++$count if @sieve[ $m ];
+ }
+
+ return $count;
+}
+
+#------------------------------------------------------------------------------
+sub run-tests()
+#------------------------------------------------------------------------------
+{
+ 'Running the test suite'.put;
+
+ for test-data.lines -> Str $line
+ {
+ my Str ($test-name, $n, $expected) = $line.split: / \| /, $TEST-FIELDS;
+
+ s/ ^ \s* (.+?) \s* $ /$0/ # Trim whitespace
+ for $test-name, $n, $expected;
+
+ is count-primes( $n.Int ), $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| 10| 4
+ Example 2| 15| 6
+ Example 3| 1| 0
+ Example 4| 25| 9
+ Large n |1000000|78498
+ END
+}
+
+###############################################################################