aboutsummaryrefslogtreecommitdiff
path: root/challenge-182/athanasius
diff options
context:
space:
mode:
authorPerlMonk-Athanasius <PerlMonk.Athanasius@gmail.com>2022-09-18 21:47:11 +1000
committerPerlMonk-Athanasius <PerlMonk.Athanasius@gmail.com>2022-09-18 21:47:11 +1000
commit8d8d6185fd05cf53c0a6d7426515a10ec254b7d4 (patch)
tree6c3c64c181bb7622ac1538026e251d4d55b2d669 /challenge-182/athanasius
parent559b0db403c98c06f39439e66a71457191c9e0e2 (diff)
downloadperlweeklychallenge-club-8d8d6185fd05cf53c0a6d7426515a10ec254b7d4.tar.gz
perlweeklychallenge-club-8d8d6185fd05cf53c0a6d7426515a10ec254b7d4.tar.bz2
perlweeklychallenge-club-8d8d6185fd05cf53c0a6d7426515a10ec254b7d4.zip
Perl & Raku solutions to Tasks 1 & 2 for Week 182
Diffstat (limited to 'challenge-182/athanasius')
-rw-r--r--challenge-182/athanasius/perl/ch-1.pl135
-rw-r--r--challenge-182/athanasius/perl/ch-2.pl225
-rw-r--r--challenge-182/athanasius/perl/paths.txt5
-rw-r--r--challenge-182/athanasius/raku/ch-1.raku112
-rw-r--r--challenge-182/athanasius/raku/ch-2.raku181
-rw-r--r--challenge-182/athanasius/raku/paths.txt5
6 files changed, 663 insertions, 0 deletions
diff --git a/challenge-182/athanasius/perl/ch-1.pl b/challenge-182/athanasius/perl/ch-1.pl
new file mode 100644
index 0000000000..6d6e899d56
--- /dev/null
+++ b/challenge-182/athanasius/perl/ch-1.pl
@@ -0,0 +1,135 @@
+#!perl
+
+###############################################################################
+=comment
+
+Perl Weekly Challenge 182
+=========================
+
+TASK #1
+-------
+*Max Index*
+
+Submitted by: Mohammad S Anwar
+
+You are given a list of integers.
+
+Write a script to find the index of the first biggest number in the list.
+
+Example
+
+ Input: @n = (5, 2, 9, 1, 7, 6)
+ Output: 2 (as 3rd element in the list is the biggest number)
+
+
+ Input: @n = (4, 2, 3, 1, 5, 0)
+ Output: 4 (as 5th element in the list is the biggest number)
+
+=cut
+###############################################################################
+
+#--------------------------------------#
+# Copyright © 2022 PerlMonk Athanasius #
+#--------------------------------------#
+
+#==============================================================================
+=comment
+
+Configuration
+-------------
+Set the constant $VERBOSE to a true value to add an explanation to the output,
+as per the Examples.
+
+=cut
+#==============================================================================
+
+use strict;
+use warnings;
+use Const::Fast;
+use Regexp::Common qw( number );
+
+const my $VERBOSE => 1;
+const my $USAGE =>
+"Usage:
+ perl $0 [<n> ...]
+
+ [<n> ...] A non-empty list of integers\n";
+
+#------------------------------------------------------------------------------
+BEGIN
+#------------------------------------------------------------------------------
+{
+ $| = 1;
+ print "\nChallenge 182, Task #1: Max Index (Perl)\n\n";
+}
+
+#==============================================================================
+MAIN:
+#==============================================================================
+{
+ my @n = parse_command_line();
+
+ printf "Input: \@n = (%s)\n", join ', ', @n;
+
+ my ($index, $max) = (0, $n[ 0 ]);
+
+ for my $i (1 .. $#n)
+ {
+ if ($n[ $i ] > $max)
+ {
+ $index = $i;
+ $max = $n[ $i ];
+ }
+ }
+
+ if ($VERBOSE)
+ {
+ printf 'Output: %d (as %d, the %s element in the list, is the ' .
+ "largest)\n", $index, $max, ordinal( $index + 1 );
+ }
+ else
+ {
+ print "Output: $index\n";
+ }
+}
+
+#------------------------------------------------------------------------------
+sub ordinal
+#------------------------------------------------------------------------------
+{
+ my ($n) = @_;
+ my $ones = $n % 10;
+ my $tens = int( $n / 10 ) % 10;
+ my $suffix = $tens == 1 ? 'th' :
+ $ones == 1 ? 'st' :
+ $ones == 2 ? 'nd' :
+ $ones == 3 ? 'rd' : 'th';
+
+ return $n . $suffix;
+}
+
+#------------------------------------------------------------------------------
+sub parse_command_line
+#------------------------------------------------------------------------------
+{
+ scalar @ARGV > 0 or error( 'No command line arguments found' );
+
+ for my $n (@ARGV)
+ {
+ $n =~ / ^ $RE{num}{int} $ /x
+ or error( qq["$n" is not a valid integer] );
+ }
+
+ return @ARGV;
+}
+
+#------------------------------------------------------------------------------
+sub error
+#------------------------------------------------------------------------------
+{
+ my ($message) = @_;
+
+ die "ERROR: $message\n$USAGE";
+}
+
+###############################################################################
diff --git a/challenge-182/athanasius/perl/ch-2.pl b/challenge-182/athanasius/perl/ch-2.pl
new file mode 100644
index 0000000000..02b13be5cd
--- /dev/null
+++ b/challenge-182/athanasius/perl/ch-2.pl
@@ -0,0 +1,225 @@
+#!perl
+
+###############################################################################
+=comment
+
+Perl Weekly Challenge 182
+=========================
+
+TASK #2
+-------
+*Common Path*
+
+Submitted by: Julien Fiegehenn
+
+Given a list of absolute Linux file paths, determine the deepest path to the
+directory that contains all of them.
+
+Example
+
+ Input:
+ /a/b/c/1/x.pl
+ /a/b/c/d/e/2/x.pl
+ /a/b/c/d/3/x.pl
+ /a/b/c/4/x.pl
+ /a/b/c/d/5/x.pl
+
+ Output:
+ /a/b/c
+
+=cut
+###############################################################################
+
+#--------------------------------------#
+# Copyright © 2022 PerlMonk Athanasius #
+#--------------------------------------#
+
+#==============================================================================
+=comment
+
+Assumptions
+-----------
+1. A path consists of directories only.
+2. The final entry in the path is a directory if and only if it is followed by
+ a path separator.
+
+Interface
+---------
+The input list of absolute Linux file paths may be either entered directly on
+the command line or contained in a text file whose name is given on the command
+line via the --file flag. If no command line arguments are given, input data is
+read from the default file "paths.txt", which contains the data in the Example.
+
+Configuration
+-------------
+The Example gives "/a/b/c" as the required output, with no separator appended
+to the final directory. This behaviour is enabled by setting the $SHOW_FINAL
+constant to a false value.
+
+However, if the only common directory happens to be root, the output will then
+be an empty string, which is misleading. To append the file path separator to
+the final directory, set $SHOW_FINAL to a true value. This will produce the
+output "/a/b/c/" for the Example, and "/" when the only common directory is
+root.
+
+=cut
+#==============================================================================
+
+use strict;
+use warnings;
+use Const::Fast;
+use Getopt::Long;
+use List::Util qw( all );
+
+const my $DEFAULT_FILE => 'paths.txt';
+const my $SEPARATOR => '/';
+const my $SHOW_FINAL => 1;
+const my $USAGE =>
+"Usage:
+ perl $0 [<paths> ...]
+ perl $0 [--file <Str>]
+
+ [<paths> ...] A list of absolute Linux file paths
+ --file <Str> Name of input file [default: '$DEFAULT_FILE']\n";
+
+#------------------------------------------------------------------------------
+BEGIN
+#------------------------------------------------------------------------------
+{
+ $| = 1;
+ print "\nChallenge 182, Task #2: Common Path (Perl)\n\n";
+}
+
+#==============================================================================
+MAIN:
+#==============================================================================
+{
+ my ($input, $str_paths) = parse_command_line();
+
+ printf "Input (%s):\n %s\n\n", $input, join "\n ", @$str_paths;
+
+ my $dir_paths = parse_string_paths( $str_paths );
+ my $common_path = find_deepest_path ( $dir_paths );
+
+ print "Output:\n $common_path\n";
+}
+
+#------------------------------------------------------------------------------
+sub find_deepest_path
+#------------------------------------------------------------------------------
+{
+ my ($dir_paths) = @_;
+ my $common_path = $SEPARATOR;
+
+ while (all { scalar @$_ > 0 } @$dir_paths)
+ {
+ my @dirs = map { shift @$_ } @$dir_paths;
+
+ if (all { $_ eq $dirs[ 0 ] } @dirs)
+ {
+ $common_path .= $dirs[ 0 ] . $SEPARATOR;
+ }
+ else
+ {
+ last;
+ }
+ }
+
+ unless ($SHOW_FINAL)
+ {
+ chop $common_path for 1 .. length $SEPARATOR;
+ }
+
+ return $common_path;
+}
+
+#------------------------------------------------------------------------------
+sub parse_string_paths
+#------------------------------------------------------------------------------
+{
+ my ($str_paths) = @_;
+ my @dir_paths;
+
+ for my $path (@$str_paths)
+ {
+ # "If LIMIT is negative, it is treated as if it were instead arbitrari-
+ # ly large; as many fields as possible are produced."
+ # -- https://perldoc.perl.org/functions/split
+
+ my @dirs = split $SEPARATOR, $path, -1;
+
+ $dirs[ 0 ] eq '' or error( qq[Path "$path" does not begin at root] );
+ shift @dirs;
+ pop @dirs; # Remove either filename or
+ # the empty string that follows a directory
+ push @dir_paths, [ @dirs ];
+ }
+
+ return \@dir_paths;
+}
+
+#------------------------------------------------------------------------------
+sub parse_command_line
+#------------------------------------------------------------------------------
+{
+ my $file;
+
+ GetOptions( 'file=s' => \$file )
+ or error( 'Invalid command line flag(s)' );
+
+ my $args = scalar @ARGV;
+ my ($input, @paths);
+
+ if (defined $file)
+ {
+ $args == 0 or error( 'Extra command line arguments found' );
+
+ $input = qq[file "$file"];
+ @paths = read_file( $file );
+ }
+ elsif ($args == 0)
+ {
+ $input = qq[file "$DEFAULT_FILE"];
+ @paths = read_file( $DEFAULT_FILE );
+ }
+ else
+ {
+ $input = 'command line';
+ @paths = @ARGV;
+ }
+
+ return ($input, \@paths);
+}
+
+#------------------------------------------------------------------------------
+sub read_file
+#------------------------------------------------------------------------------
+{
+ my ($filename) = @_;
+
+ open my $fh, '<', $filename
+ or error( qq[Can't open file "$filename" for reading] );
+
+ my @lines;
+
+ while (my $line = <$fh>)
+ {
+ chomp $line;
+ push @lines, $line;
+ }
+
+ close $fh or die qq[Can't close file "$filename"];
+
+ return @lines;
+}
+
+#------------------------------------------------------------------------------
+sub error
+#------------------------------------------------------------------------------
+{
+ my ($message) = @_;
+
+ die "ERROR: $message\n$USAGE";
+}
+
+###############################################################################
diff --git a/challenge-182/athanasius/perl/paths.txt b/challenge-182/athanasius/perl/paths.txt
new file mode 100644
index 0000000000..e0678fd698
--- /dev/null
+++ b/challenge-182/athanasius/perl/paths.txt
@@ -0,0 +1,5 @@
+/a/b/c/1/x.pl
+/a/b/c/d/e/2/x.pl
+/a/b/c/d/3/x.pl
+/a/b/c/4/x.pl
+/a/b/c/d/5/x.pl
diff --git a/challenge-182/athanasius/raku/ch-1.raku b/challenge-182/athanasius/raku/ch-1.raku
new file mode 100644
index 0000000000..1766844788
--- /dev/null
+++ b/challenge-182/athanasius/raku/ch-1.raku
@@ -0,0 +1,112 @@
+use v6d;
+
+###############################################################################
+=begin comment
+
+Perl Weekly Challenge 182
+=========================
+
+TASK #1
+-------
+*Max Index*
+
+Submitted by: Mohammad S Anwar
+
+You are given a list of integers.
+
+Write a script to find the index of the first biggest number in the list.
+
+Example
+
+ Input: @n = (5, 2, 9, 1, 7, 6)
+ Output: 2 (as 3rd element in the list is the biggest number)
+
+
+ Input: @n = (4, 2, 3, 1, 5, 0)
+ Output: 4 (as 5th element in the list is the biggest number)
+
+=end comment
+###############################################################################
+
+#--------------------------------------#
+# Copyright © 2022 PerlMonk Athanasius #
+#--------------------------------------#
+
+#==============================================================================
+=begin comment
+
+Configuration
+-------------
+Set the constant $VERBOSE to True to add an explanation to the output, as per
+the Examples.
+
+=end comment
+#==============================================================================
+
+my Bool constant $VERBOSE = True;
+
+#------------------------------------------------------------------------------
+BEGIN
+#------------------------------------------------------------------------------
+{
+ "\nChallenge 182, Task #1: Max Index (Raku)\n".put;
+}
+
+#==============================================================================
+sub MAIN
+(
+ *@n where { .elems > 0 && .all ~~ Int:D } #= A non-empty list of integers
+)
+#==============================================================================
+{
+ "Input: @n = (%s)\n".printf: @n.join: ', ';
+
+ my Int $max = @n.max;
+ my UInt $index;
+
+ for 0 .. @n.end -> UInt $i
+ {
+ if @n[ $i ] == $max
+ {
+ $index = $i;
+ last;
+ }
+ }
+
+ if $VERBOSE
+ {
+ "Output: %d (as %d, the %s element in the list, is the largest)\n".\
+ printf: $index, $max, ordinal( $index + 1 );
+ }
+ else
+ {
+ "Output: $index".put;
+ }
+}
+
+#------------------------------------------------------------------------------
+sub ordinal( UInt:D $n --> Str:D )
+#------------------------------------------------------------------------------
+{
+ my UInt $ones = $n % 10;
+ my UInt $tens = ($n / 10).floor % 10;
+ my Str $suffix = $tens == 1 ?? 'th' !!
+ $ones == 1 ?? 'st' !!
+ $ones == 2 ?? 'nd' !!
+ $ones == 3 ?? 'rd' !! 'th';
+
+ return $n ~ $suffix;
+}
+
+#------------------------------------------------------------------------------
+sub USAGE()
+#------------------------------------------------------------------------------
+{
+ my Str $usage = $*USAGE;
+
+ $usage ~~ s/ ($*PROGRAM-NAME) /raku $0/;
+
+ $usage.put;
+}
+
+###############################################################################
diff --git a/challenge-182/athanasius/raku/ch-2.raku b/challenge-182/athanasius/raku/ch-2.raku
new file mode 100644
index 0000000000..60912479a9
--- /dev/null
+++ b/challenge-182/athanasius/raku/ch-2.raku
@@ -0,0 +1,181 @@
+use v6d;
+
+###############################################################################
+=begin comment
+
+Perl Weekly Challenge 182
+=========================
+
+TASK #2
+-------
+*Common Path*
+
+Submitted by: Julien Fiegehenn
+
+Given a list of absolute Linux file paths, determine the deepest path to the
+directory that contains all of them.
+
+Example
+
+ Input:
+ /a/b/c/1/x.pl
+ /a/b/c/d/e/2/x.pl
+ /a/b/c/d/3/x.pl
+ /a/b/c/4/x.pl
+ /a/b/c/d/5/x.pl
+
+ Output:
+ /a/b/c
+
+=end comment
+###############################################################################
+
+#--------------------------------------#
+# Copyright © 2022 PerlMonk Athanasius #
+#--------------------------------------#
+
+#==============================================================================
+=begin comment
+
+Assumptions
+-----------
+1. A path consists of directories only.
+2. The final entry in the path is a directory if and only if it is followed by
+ a path separator.
+
+Interface
+---------
+The input list of absolute Linux file paths may be either entered directly on
+the command line or contained in a text file whose name is given on the command
+line via the --file flag. If no command line arguments are given, input data is
+read from the default file "paths.txt", which contains the data in the Example.
+
+Configuration
+-------------
+The Example gives "/a/b/c" as the required output, with no separator appended
+to the final directory. This behaviour is enabled by setting the $SHOW-FINAL
+constant to False.
+
+However, if the only common directory happens to be root, the output will then
+be an empty string, which is misleading. To append the file path separator to
+the final directory, set $SHOW-FINAL to True. This will produce the output
+"/a/b/c/" for the Example, and "/" when the only common directory is root.
+
+=end comment
+#==============================================================================
+
+my Str constant $DEFAULT-FILE = 'paths.txt';
+my Str constant $SEPARATOR = '/';
+my Bool constant $SHOW-FINAL = True;
+
+#------------------------------------------------------------------------------
+BEGIN
+#------------------------------------------------------------------------------
+{
+ "\nChallenge 182, Task #2: Common Path (Raku)\n".put;
+}
+
+#==============================================================================
+multi sub MAIN
+(
+ *@paths where { .elems > 0 } #= A list of absolute Linux file paths
+)
+#==============================================================================
+{
+ main( 'command line', @paths );
+}
+
+#==============================================================================
+multi sub MAIN
+(
+ Str:D :$file where *.IO.f = $DEFAULT-FILE #= Name of input file
+)
+#==============================================================================
+{
+ my Str @paths = $file.IO.lines;
+
+ @paths > 0 or error( 'No paths found' );
+
+ main( qq[file "$file"], @paths );
+}
+
+#------------------------------------------------------------------------------
+sub main( Str:D $input, Array:D[Str:D] $str-paths )
+#------------------------------------------------------------------------------
+{
+ "Input (%s):\n %s\n\n".printf: $input, $str-paths.join: "\n ";
+
+ my Array[Str] @dir-paths = parse-string-paths( $str-paths );
+ my Str $common-path = find-deepest-path\( @dir-paths );
+
+ "Output:\n $common-path".put;
+}
+
+#------------------------------------------------------------------------------
+sub parse-string-paths( Array:D[Str:D] $str-paths --> Array:D[Array:D[Str:D]] )
+#------------------------------------------------------------------------------
+{
+ my Array[Str] @dir-paths;
+
+ for @$str-paths -> Str $path
+ {
+ my Str @dirs = $path.split: $SEPARATOR;
+
+ @dirs[ 0 ] eq '' or error( qq[Path "$path" does not begin at root] );
+ @dirs.shift;
+ @dirs.pop; # Remove either filename or
+ # the empty string that follows a directory
+ @dir-paths.push: @dirs;
+ }
+
+ return @dir-paths;
+}
+
+#------------------------------------------------------------------------------
+sub find-deepest-path( Array:D[Array:D[Str:D]] $dir-paths --> Str:D )
+#------------------------------------------------------------------------------
+{
+ my Str $common-path = $SEPARATOR;
+
+ while @$dir-paths.all.elems > 0
+ {
+ my Str @dirs = @$dir-paths.map: { .shift };
+
+ if @dirs.all eq @dirs[ 0 ]
+ {
+ $common-path ~= @dirs[ 0 ] ~ $SEPARATOR;
+ }
+ else
+ {
+ last;
+ }
+ }
+
+ $common-path .= chop: $SEPARATOR.chars unless $SHOW-FINAL;
+
+ return $common-path;
+}
+
+#------------------------------------------------------------------------------
+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-182/athanasius/raku/paths.txt b/challenge-182/athanasius/raku/paths.txt
new file mode 100644
index 0000000000..e0678fd698
--- /dev/null
+++ b/challenge-182/athanasius/raku/paths.txt
@@ -0,0 +1,5 @@
+/a/b/c/1/x.pl
+/a/b/c/d/e/2/x.pl
+/a/b/c/d/3/x.pl
+/a/b/c/4/x.pl
+/a/b/c/d/5/x.pl