diff options
| author | PerlMonk-Athanasius <PerlMonk.Athanasius@gmail.com> | 2022-09-18 21:47:11 +1000 |
|---|---|---|
| committer | PerlMonk-Athanasius <PerlMonk.Athanasius@gmail.com> | 2022-09-18 21:47:11 +1000 |
| commit | 8d8d6185fd05cf53c0a6d7426515a10ec254b7d4 (patch) | |
| tree | 6c3c64c181bb7622ac1538026e251d4d55b2d669 /challenge-182/athanasius | |
| parent | 559b0db403c98c06f39439e66a71457191c9e0e2 (diff) | |
| download | perlweeklychallenge-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.pl | 135 | ||||
| -rw-r--r-- | challenge-182/athanasius/perl/ch-2.pl | 225 | ||||
| -rw-r--r-- | challenge-182/athanasius/perl/paths.txt | 5 | ||||
| -rw-r--r-- | challenge-182/athanasius/raku/ch-1.raku | 112 | ||||
| -rw-r--r-- | challenge-182/athanasius/raku/ch-2.raku | 181 | ||||
| -rw-r--r-- | challenge-182/athanasius/raku/paths.txt | 5 |
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 |
