aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--challenge-272/athanasius/perl/ch-1.pl176
-rw-r--r--challenge-272/athanasius/perl/ch-2.pl231
-rw-r--r--challenge-272/athanasius/raku/ch-1.raku172
-rw-r--r--challenge-272/athanasius/raku/ch-2.raku204
4 files changed, 783 insertions, 0 deletions
diff --git a/challenge-272/athanasius/perl/ch-1.pl b/challenge-272/athanasius/perl/ch-1.pl
new file mode 100644
index 0000000000..eb28c4ea49
--- /dev/null
+++ b/challenge-272/athanasius/perl/ch-1.pl
@@ -0,0 +1,176 @@
+#!perl
+
+################################################################################
+=comment
+
+Perl Weekly Challenge 272
+=========================
+
+TASK #1
+-------
+*Defang IP Address*
+
+Submitted by: Mohammad Sajid Anwar
+
+You are given a valid IPv4 address.
+
+Write a script to return the defanged version of the given IP address.
+
+ A defanged IP address replaces every period “.” with “[.]".
+
+Example 1
+
+ Input: $ip = "1.1.1.1"
+ Output: "1[.]1[.]1[.]1"
+
+Example 2
+
+ Input: $ip = "255.101.1.0"
+ Output: "255[.]101[.]1[.]0"
+
+=cut
+################################################################################
+
+#--------------------------------------#
+# Copyright © 2024 PerlMonk Athanasius #
+#--------------------------------------#
+
+#===============================================================================
+=comment
+
+Assumptions
+-----------
+1. The given IP address is in quad-dotted notation: 4 decimal numbers (octets),
+ each in the range 0 to 255, separated by dots (periods).
+2. For octets, leading zeros are allowed, but leading "+" signs are not.
+
+Interface
+---------
+1. If no command-line arguments are given, the test suite is run. Otherwise:
+2. The IP to be defanged is entered on the command-line as a single string.
+
+=cut
+#===============================================================================
+
+use v5.32.1; # Enables strictures
+use warnings;
+use Const::Fast;
+use Regexp::Common qw( number );
+use Test::More;
+
+const my $OCTET_MAX => 255;
+const my $USAGE => <<END;
+Usage:
+ perl $0 <ip>
+ perl $0
+
+ <ip> A valid IP address in quad-dotted notation
+END
+
+#-------------------------------------------------------------------------------
+BEGIN
+#-------------------------------------------------------------------------------
+{
+ $| = 1;
+ print "\nChallenge 272, Task #1: Defang IP Address (Perl)\n\n";
+}
+
+#===============================================================================
+MAIN:
+#===============================================================================
+{
+ my $argc = scalar @ARGV;
+
+ if ($argc == 0)
+ {
+ run_tests();
+ }
+ elsif ($argc == 1)
+ {
+ my $ip = $ARGV[ 0 ];
+
+ is_valid_ip( $ip ) or error( qq[Invalid IP "$ip"] );
+
+ print qq[Input: \$ip = "$ip"\n];
+
+ my $defanged = defang( $ip );
+
+ print qq[Output: "$defanged"\n];
+ }
+ else
+ {
+ error( "Expected 1 or 0 command-line arguments, found $argc" );
+ }
+}
+
+#-------------------------------------------------------------------------------
+sub defang
+#-------------------------------------------------------------------------------
+{
+ my ($ip) = @_;
+
+ return $ip =~ s{ \. }{[.]}grx;
+}
+
+#-------------------------------------------------------------------------------
+sub is_valid_ip
+#-------------------------------------------------------------------------------
+{
+ my ($ip) = @_;
+
+ return 0 unless $ip =~ / ^ [0-9.]+ $ /x;
+
+ my @octets = split / \. /x, $ip;
+
+ return 0 unless scalar @octets == 4;
+
+ for (@octets)
+ {
+ return 0 unless m/ ^ $RE{num}{int} $ /x && 0 <= $_ <= $OCTET_MAX;
+ }
+
+ return 1;
+}
+
+#-------------------------------------------------------------------------------
+sub run_tests
+#-------------------------------------------------------------------------------
+{
+ print "Running the test suite\n";
+
+ while (my $line = <DATA>)
+ {
+ chomp $line;
+
+ my ($test_name, $ip, $expected) = split / \| /x, $line;
+
+ for ($test_name, $ip, $expected)
+ {
+ s/ ^ \s+ //x;
+ s/ \s+ $ //x;
+ }
+
+ is_valid_ip( $ip ) or error( qq[Invalid IP "$ip"] );
+
+ my $defanged = defang( $ip );
+
+ is $defanged, $expected, $test_name;
+ }
+
+ done_testing;
+}
+
+#-------------------------------------------------------------------------------
+sub error
+#-------------------------------------------------------------------------------
+{
+ my ($message) = @_;
+
+ die "ERROR: $message\n$USAGE";
+}
+
+################################################################################
+
+__DATA__
+Example 1|1.1.1.1 |1[.]1[.]1[.]1
+Example 2|255.101.1.0|255[.]101[.]1[.]0
diff --git a/challenge-272/athanasius/perl/ch-2.pl b/challenge-272/athanasius/perl/ch-2.pl
new file mode 100644
index 0000000000..f2c9322ea9
--- /dev/null
+++ b/challenge-272/athanasius/perl/ch-2.pl
@@ -0,0 +1,231 @@
+#!perl
+
+################################################################################
+=comment
+
+Perl Weekly Challenge 272
+=========================
+
+TASK #2
+-------
+*String Score*
+
+Submitted by: Mohammad Sajid Anwar
+
+You are given a string, $str.
+
+Write a script to return the score of the given string.
+
+ The score of a string is defined as the sum of the absolute difference
+ between the ASCII values of adjacent characters.
+
+Example 1
+
+ Input: $str = "hello"
+ Output: 13
+
+ ASCII values of characters:
+ h = 104
+ e = 101
+ l = 108
+ l = 108
+ o = 111
+
+ Score => |104 - 101| + |101 - 108| + |108 - 108| + |108 - 111|
+ => 3 + 7 + 0 + 3
+ => 13
+
+Example 2
+
+ Input: "perl"
+ Output: 30
+
+ ASCII values of characters:
+ p = 112
+ e = 101
+ r = 114
+ l = 108
+
+ Score => |112 - 101| + |101 - 114| + |114 - 108|
+ => 11 + 13 + 6
+ => 30
+
+Example 3
+
+ Input: "raku"
+ Output: 37
+
+ ASCII values of characters:
+ r = 114
+ a = 97
+ k = 107
+ u = 117
+
+ Score => |114 - 97| + |97 - 107| + |107 - 117|
+ => 17 + 10 + 10
+ => 37
+
+=cut
+################################################################################
+
+#--------------------------------------#
+# Copyright © 2024 PerlMonk Athanasius #
+#--------------------------------------#
+
+#===============================================================================
+=comment
+
+Assumption
+----------
+The input string may contain only printable ASCII characters, in the range ' '
+(space, value 0x20 = 32) to '~' (tilde, value 0x7E = 176).
+
+Interface
+---------
+1. If no command-line arguments are given, the test suite is run. Otherwise:
+2. The input string is entered on the command-line.
+
+Note
+----
+Command-line input is assumed to be ASCII-encoded. The input is checked for non-
+ASCII characters; however, if the input is in a different encoding, this might
+not be detected. For example, when "perl ch-2.pl ΓΔ" is entered at a DOS prompt
+under Windows 11, the script receives the input string as "G?", which passes the
+ASCII check.
+
+=cut
+#===============================================================================
+
+use v5.32.1; # Enables strictures
+use warnings;
+use Const::Fast;
+use Test::More;
+
+use constant DEBUG => 0;
+
+const my $ASCII_MAX => '~';
+const my $ASCII_MIN => ' ';
+const my $USAGE => <<END;
+Usage:
+ perl $0 <str>
+ perl $0
+
+ <str> A string of printable ASCII characters
+END
+
+#-------------------------------------------------------------------------------
+BEGIN
+#-------------------------------------------------------------------------------
+{
+ $| = 1;
+ print "\nChallenge 272, Task #2: String Score (Perl)\n\n";
+}
+
+#===============================================================================
+MAIN:
+#===============================================================================
+{
+ my $argc = scalar @ARGV;
+
+ if ($argc == 0)
+ {
+ run_tests();
+ }
+ elsif ($argc == 1)
+ {
+ my $str = $ARGV[ 0 ];
+
+ validate_ascii( $str );
+
+ print qq[Input: \$str = "$str"\n];
+
+ my $score = find_string_score( $str );
+
+ print "Output: $score\n";
+ }
+ else
+ {
+ error( "Expected 1 or 0 command-line arguments, found $argc" );
+ }
+}
+
+#-------------------------------------------------------------------------------
+sub find_string_score
+#-------------------------------------------------------------------------------
+{
+ my ($str) = @_;
+ my @ascii = map { ord() } split //, $str;
+ my $score = 0;
+
+ for my $i (0 .. $#ascii - 1)
+ {
+ $score += abs( $ascii[ $i ] - $ascii[ $i + 1 ] );
+ }
+
+ return $score;
+}
+
+#-------------------------------------------------------------------------------
+sub validate_ascii
+#-------------------------------------------------------------------------------
+{
+ my ($str) = @_;
+
+ if (DEBUG)
+ {
+ my @ords = map { ord() } split //, $str;
+
+ printf qq[DEBUG: \$str = "%s" (%s)\n],
+ $str, join ' ', map { sprintf '%x', $_ } @ords;
+ }
+
+ for (split //, $str)
+ {
+ $ASCII_MIN le $_ le $ASCII_MAX
+ or error( 'chr(' . ord . ') is not a printable ASCII character');
+ }
+}
+
+#-------------------------------------------------------------------------------
+sub run_tests
+#-------------------------------------------------------------------------------
+{
+ print "Running the test suite\n";
+
+ while (my $line = <DATA>)
+ {
+ chomp $line;
+
+ my ($test_name, $str, $expected) = split / \| /x, $line;
+
+ for ($test_name, $str, $expected)
+ {
+ s/ ^ \s+ //x;
+ s/ \s+ $ //x;
+ }
+
+ validate_ascii( $str ) if DEBUG;
+
+ my $score = find_string_score( $str );
+
+ is $score, $expected, $test_name;
+ }
+
+ done_testing;
+}
+
+#-------------------------------------------------------------------------------
+sub error
+#-------------------------------------------------------------------------------
+{
+ my ($message) = @_;
+
+ die "ERROR: $message\n$USAGE";
+}
+
+################################################################################
+
+__DATA__
+Example 1|hello|13
+Example 2|perl |30
+Example 3|raku |37
diff --git a/challenge-272/athanasius/raku/ch-1.raku b/challenge-272/athanasius/raku/ch-1.raku
new file mode 100644
index 0000000000..abb4b5e7b4
--- /dev/null
+++ b/challenge-272/athanasius/raku/ch-1.raku
@@ -0,0 +1,172 @@
+use v6d;
+
+################################################################################
+=begin comment
+
+Perl Weekly Challenge 272
+=========================
+
+TASK #1
+-------
+*Defang IP Address*
+
+Submitted by: Mohammad Sajid Anwar
+
+You are given a valid IPv4 address.
+
+Write a script to return the defanged version of the given IP address.
+
+ A defanged IP address replaces every period “.” with “[.]".
+
+Example 1
+
+ Input: $ip = "1.1.1.1"
+ Output: "1[.]1[.]1[.]1"
+
+Example 2
+
+ Input: $ip = "255.101.1.0"
+ Output: "255[.]101[.]1[.]0"
+
+=end comment
+################################################################################
+
+#--------------------------------------#
+# Copyright © 2024 PerlMonk Athanasius #
+#--------------------------------------#
+
+#===============================================================================
+=begin comment
+
+Assumptions
+-----------
+1. The given IP address is in quad-dotted notation: 4 decimal numbers (octets),
+ each in the range 0 to 255, separated by dots (periods).
+2. For octets, leading zeros are allowed, but leading "+" signs are not.
+
+Interface
+---------
+1. If no command-line arguments are given, the test suite is run. Otherwise:
+2. The IP to be defanged is entered on the command-line as a single string.
+
+=end comment
+#===============================================================================
+
+use Test;
+
+my UInt constant OCTET-MAX = 255;
+
+#-------------------------------------------------------------------------------
+BEGIN
+#-------------------------------------------------------------------------------
+{
+ "\nChallenge 272, Task #1: Defang IP Address (Raku)\n".put;
+}
+
+#===============================================================================
+multi sub MAIN
+(
+ Str:D $ip #= A valid IP address in quad-dotted notation
+)
+#===============================================================================
+{
+ is-valid-ip( $ip ) or error( qq[Invalid IP "$ip"] );
+
+ qq[Input: \$ip = "$ip"].put;
+
+ my Str $defanged = defang( $ip );
+
+ qq[Output: "$defanged"].put;
+}
+
+#===============================================================================
+multi sub MAIN() # No input: run the test suite
+#===============================================================================
+{
+ run-tests();
+}
+
+#-------------------------------------------------------------------------------
+sub defang( Str:D $ip --> Str:D )
+#-------------------------------------------------------------------------------
+{
+ return S:g{ \. } = '[.]' with $ip;
+}
+
+#-------------------------------------------------------------------------------
+sub is-valid-ip( Str:D $ip --> Bool:D )
+#-------------------------------------------------------------------------------
+{
+ return False unless $ip ~~ / ^ <[ 0..9 . ]>+ $ /;
+
+ my Str @octets = $ip.split: '.', :skip-empty;
+
+ return False unless @octets.elems == 4;
+
+ for @octets
+ {
+ return False unless +$_ ~~ UInt:D && +$_ <= OCTET-MAX;
+ }
+
+ return True;
+}
+
+#-------------------------------------------------------------------------------
+sub run-tests()
+#-------------------------------------------------------------------------------
+{
+ 'Running the test suite'.put;
+
+ for test-data.lines -> Str $line
+ {
+ my Str ($test-name, $ip, $expected) = $line.split: / \| /;
+
+ for $test-name, $ip, $expected
+ {
+ s/ ^ \s+ //;
+ s/ \s+ $ //;
+ }
+
+ is-valid-ip( $ip ) or error( qq[Invalid IP "$ip"] );
+
+ my Str $defanged = defang( $ip );
+
+ is $defanged, $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|1.1.1.1 |1[.]1[.]1[.]1
+ Example 2|255.101.1.0|255[.]101[.]1[.]0
+ END
+}
+
+################################################################################
diff --git a/challenge-272/athanasius/raku/ch-2.raku b/challenge-272/athanasius/raku/ch-2.raku
new file mode 100644
index 0000000000..7c9714edae
--- /dev/null
+++ b/challenge-272/athanasius/raku/ch-2.raku
@@ -0,0 +1,204 @@
+use v6d;
+
+################################################################################
+=begin comment
+
+Perl Weekly Challenge 272
+=========================
+
+TASK #2
+-------
+*String Score*
+
+Submitted by: Mohammad Sajid Anwar
+
+You are given a string, $str.
+
+Write a script to return the score of the given string.
+
+ The score of a string is defined as the sum of the absolute difference
+ between the ASCII values of adjacent characters.
+
+Example 1
+
+ Input: $str = "hello"
+ Output: 13
+
+ ASCII values of characters:
+ h = 104
+ e = 101
+ l = 108
+ l = 108
+ o = 111
+
+ Score => |104 - 101| + |101 - 108| + |108 - 108| + |108 - 111|
+ => 3 + 7 + 0 + 3
+ => 13
+
+Example 2
+
+ Input: "perl"
+ Output: 30
+
+ ASCII values of characters:
+ p = 112
+ e = 101
+ r = 114
+ l = 108
+
+ Score => |112 - 101| + |101 - 114| + |114 - 108|
+ => 11 + 13 + 6
+ => 30
+
+Example 3
+
+ Input: "raku"
+ Output: 37
+
+ ASCII values of characters:
+ r = 114
+ a = 97
+ k = 107
+ u = 117
+
+ Score => |114 - 97| + |97 - 107| + |107 - 117|
+ => 17 + 10 + 10
+ => 37
+
+=end comment
+################################################################################
+
+#--------------------------------------#
+# Copyright © 2024 PerlMonk Athanasius #
+#--------------------------------------#
+
+#===============================================================================
+=begin comment
+
+Assumptions
+-----------
+1. Command-line input is assumed to be ASCII-encoded.
+2. The input string may contain only printable ASCII characters, in the range
+ ' ' (space, value 0x20 = 32) to '~' (tilde, value 0x7E = 176).
+
+Interface
+---------
+1. If no command-line arguments are given, the test suite is run. Otherwise:
+2. The input string is entered on the command-line.
+
+=end comment
+#===============================================================================
+
+use Test;
+
+my Str constant ASCII-MAX = '~';
+my Str constant ASCII-MIN = ' ';
+
+#-------------------------------------------------------------------------------
+BEGIN
+#-------------------------------------------------------------------------------
+{
+ "\nChallenge 272, Task #2: String Score (Raku)\n".put;
+}
+
+#===============================================================================
+multi sub MAIN
+(
+ Str:D $str #= A string of printable ASCII characters
+)
+#===============================================================================
+{
+ for $str.split: '', :skip-empty
+ {
+ ASCII-MIN le $_ le ASCII-MAX
+ or error( qq["$_" (chr { .ord.base( 16 ) }) is not a printable ] ~
+ 'ASCII character' );
+ }
+
+ qq[Input: \$str = "$str"].put;
+
+ my UInt $score = find-string-score( $str );
+
+ "Output: $score".put;
+}
+
+#===============================================================================
+multi sub MAIN() # No input: run the test suite
+#===============================================================================
+{
+ run-tests();
+}
+
+#-------------------------------------------------------------------------------
+sub find-string-score( Str:D $str --> UInt:D )
+#-------------------------------------------------------------------------------
+{
+ my UInt @ascii = $str.split( '', :skip-empty ).map: { .ord };
+ my UInt $score = 0;
+
+ for 0 .. @ascii.end - 1 -> UInt $i
+ {
+ $score += ( @ascii[ $i ] - @ascii[ $i + 1 ] ).abs;
+ }
+
+ return $score;
+}
+
+#-------------------------------------------------------------------------------
+sub run-tests()
+#-------------------------------------------------------------------------------
+{
+ 'Running the test suite'.put;
+
+ for test-data.lines -> Str $line
+ {
+ my Str ($test-name, $str, $expected) = $line.split: / \| /;
+
+ for $test-name, $str, $expected
+ {
+ s/ ^ \s+ //;
+ s/ \s+ $ //;
+ }
+
+ my UInt $score = find-string-score( $str );
+
+ is $score, $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|hello|13
+ Example 2|perl |30
+ Example 3|raku |37
+ END
+}
+
+################################################################################