diff options
| author | holli-holzer <holli.holzer@gmail.com> | 2019-09-25 22:07:40 +0200 |
|---|---|---|
| committer | holli-holzer <holli.holzer@gmail.com> | 2019-09-25 22:07:40 +0200 |
| commit | 3ea4c71923fa3efa6126bb82f6478c54f02208e4 (patch) | |
| tree | 095f983eef6db7289c5d825708db817dfeed847d /challenge-026 | |
| parent | fb785b17a1358135bf6d1a366c2c4df59b419091 (diff) | |
| parent | 38173c385fb4c04bfc50cdf40fee15e8cb6901e1 (diff) | |
| download | perlweeklychallenge-club-3ea4c71923fa3efa6126bb82f6478c54f02208e4.tar.gz perlweeklychallenge-club-3ea4c71923fa3efa6126bb82f6478c54f02208e4.tar.bz2 perlweeklychallenge-club-3ea4c71923fa3efa6126bb82f6478c54f02208e4.zip | |
Merge remote-tracking branch 'upstream/master'
Diffstat (limited to 'challenge-026')
52 files changed, 1360 insertions, 47 deletions
diff --git a/challenge-026/adam-russell/blog.txt b/challenge-026/adam-russell/blog.txt new file mode 100644 index 0000000000..b0d5a96b5c --- /dev/null +++ b/challenge-026/adam-russell/blog.txt @@ -0,0 +1 @@ +https://adamcrussell.livejournal.com/9318.html diff --git a/challenge-026/adam-russell/perl5/ch-1.pl b/challenge-026/adam-russell/perl5/ch-1.pl new file mode 100644 index 0000000000..27b6048ea5 --- /dev/null +++ b/challenge-026/adam-russell/perl5/ch-1.pl @@ -0,0 +1,44 @@ +use strict; +use warnings; +## +# Create a script that accepts two strings, let us call it them "stones" and "jewels". +# It should print the count of the "alphabet" from "stones" found in "jewels". +## + +sub contains_remove{ + my($c) = @_; + return sub{ + my($word) = @_; + $word =~ s/$c//; + return $word; + } +} + +sub make_checks{ + my($word) = @_; + my @letters = split(//, $word); + my @checks; + for my $c (@letters){ + push @checks, contains_remove($c); + } + return @checks; +} + +sub check_jewels{ + my($jewels, $checks) = @_; + my $count = 0; + while(@{$checks}){ + my $check = pop @{$checks}; + my $c = $check->($jewels); + $count += (length($jewels) - length($c)); + } + return $count; +} + +MAIN:{ + my($stones, $jewels) = ($ARGV[0], $ARGV[1]); + chomp($stones); + chomp($jewels); + my @checks = make_checks($stones); + print check_jewels($jewels, \@checks) . "\n"; +} diff --git a/challenge-026/adam-russell/perl5/ch-2.pl b/challenge-026/adam-russell/perl5/ch-2.pl new file mode 100644 index 0000000000..75d0e699c5 --- /dev/null +++ b/challenge-026/adam-russell/perl5/ch-2.pl @@ -0,0 +1,35 @@ +use strict; +use warnings; +## +# Create a script that prints mean angles of the given list of angles in degrees. +## +use constant PI => atan2(1,1) * 4; + +sub deg2rad { + my($degrees) = @_; + return ($degrees / 180) * PI; +} + +sub rad2deg { + my($radians) = @_; + return ($radians / PI) * 180; +} + +sub compute_mean_angle{ + my(@angles) = @_; + my $sum = 0; + map { $sum += $_ } map { sin($_) } @angles; + my $sin_mean = $sum / @angles; + $sum = 0; + map { $sum += $_ } map { cos($_) } @angles; + my $cos_mean = $sum / @angles; + return atan2($sin_mean, $cos_mean) if $sin_mean > 0 && $cos_mean > 0; + return atan2($sin_mean, $cos_mean) + deg2rad(180) if $cos_mean < 0; + return atan2($sin_mean, $cos_mean) + deg2rad(360) if $sin_mean < 0 && $cos_mean > 0; +} + + +MAIN:{ + my @angles = map { deg2rad($_) } @ARGV[0 .. (@ARGV - 1)]; + print rad2deg(compute_mean_angle(@angles)) . "\n"; +} diff --git a/challenge-026/arne-sommer/blog.txt b/challenge-026/arne-sommer/blog.txt new file mode 100644 index 0000000000..dd665e7af0 --- /dev/null +++ b/challenge-026/arne-sommer/blog.txt @@ -0,0 +1 @@ +https://perl6.eu/string-angling.html diff --git a/challenge-026/arne-sommer/perl6/ch-1.p6 b/challenge-026/arne-sommer/perl6/ch-1.p6 new file mode 100755 index 0000000000..ab31fa021c --- /dev/null +++ b/challenge-026/arne-sommer/perl6/ch-1.p6 @@ -0,0 +1,7 @@ +#! /usr/bin/env perl6 + +subset AtoZ of Str where /^ <[A .. Z a .. z]>+ $/; + +unit sub MAIN (AtoZ $alphabet, AtoZ $string); + +say ($alphabet.comb.Set ⊍ $string.comb.Bag).Int; diff --git a/challenge-026/arne-sommer/perl6/ch-2.p6 b/challenge-026/arne-sommer/perl6/ch-2.p6 new file mode 100755 index 0000000000..916424e518 --- /dev/null +++ b/challenge-026/arne-sommer/perl6/ch-2.p6 @@ -0,0 +1,15 @@ +#! /usr/bin/env perl6 + +unit sub MAIN (*@angles); + +my \n = @angles.elems; +my @rad = @angles.map(* * pi / 180); +my \s = @rad.map(*.sin).sum / n; +my \c = @rad.map(*.cos).sum / n; +my $mean = atan2( s / c ) * 180 / pi; + +if c < 0 { $mean += 180; } +elsif s < 0 { $mean += 360; } + +say "mean: $mean"; + diff --git a/challenge-026/arne-sommer/perl6/stringcounter-loop b/challenge-026/arne-sommer/perl6/stringcounter-loop new file mode 100755 index 0000000000..67ffd13b47 --- /dev/null +++ b/challenge-026/arne-sommer/perl6/stringcounter-loop @@ -0,0 +1,15 @@ +#! /usr/bin/env perl6 + +unit sub MAIN (Str $alphabet, Str $string, :$verbose); + +my $count = 0; + +for $alphabet.comb.unique -> $letter +{ + my $current = $string.comb.grep(* eq $letter).elems; + $count += $current; + say "$letter: $current" if $verbose; +} + +say $count; + diff --git a/challenge-026/arne-sommer/perl6/stringcounter-map b/challenge-026/arne-sommer/perl6/stringcounter-map new file mode 100755 index 0000000000..82b1280e79 --- /dev/null +++ b/challenge-026/arne-sommer/perl6/stringcounter-map @@ -0,0 +1,8 @@ +#! /usr/bin/env perl6 + +unit sub MAIN (Str $alphabet, Str $string); + +say $alphabet.comb.unique.map( { $string.comb.grep(* eq $_ ) } ).sum; + + + diff --git a/challenge-026/arne-sommer/perl6/stringcounter-map-oneliner b/challenge-026/arne-sommer/perl6/stringcounter-map-oneliner new file mode 100755 index 0000000000..a0e6945ef4 --- /dev/null +++ b/challenge-026/arne-sommer/perl6/stringcounter-map-oneliner @@ -0,0 +1,6 @@ +#! /usr/bin/env perl6 + +say @*ARGS[0].comb.unique.map( { @*ARGS[1].comb.grep(* eq $_ ) } ).sum; + + + diff --git a/challenge-026/arne-sommer/perl6/stringcounter-subset b/challenge-026/arne-sommer/perl6/stringcounter-subset new file mode 100755 index 0000000000..35d3000a56 --- /dev/null +++ b/challenge-026/arne-sommer/perl6/stringcounter-subset @@ -0,0 +1,7 @@ +#! /usr/bin/env perl6 + +subset AtoZ of Str where /^ <[A .. Z a .. z]>+ $/; + +unit sub MAIN (AtoZ $alphabet, AtoZ $string); + +say $alphabet.comb.unique.map( { $string.comb.grep(* eq $_ ) } ).sum; diff --git a/challenge-026/athanasius/perl5/ch-1.pl b/challenge-026/athanasius/perl5/ch-1.pl new file mode 100644 index 0000000000..e3682b69ca --- /dev/null +++ b/challenge-026/athanasius/perl5/ch-1.pl @@ -0,0 +1,86 @@ +#!perl + +################################################################################ +=comment + +Perl Weekly Challenge 026 +========================= + +Task #1 +------- +Create a script that accepts two strings, let us call it, *"stones"* and +*"jewels"*. It should print the count of "alphabet" from the string *"stones"* +found in the string *"jewels"*. For example, if your *stones* is *"chancellor"* +and *"jewels"* is *"chocolate"*, then the script should print *"8"*. To keep it +simple, only A-Z,a-z characters are acceptable. Also make the comparison case +sensitive. + +=cut +################################################################################ + +#--------------------------------------# +# Copyright © 2019 PerlMonk Athanasius # +#--------------------------------------# + +use strict; +use warnings; +use Const::Fast; +use Getopt::Long; + +const my $ALPHA => qr{ [A-Za-z] }x; +const my $STONES => 'chancellor'; +const my $JEWELS => 'chocolate'; +const my $USAGE => "USAGE: perl $0 [--stones=<Str>] [--jewels=<Str>] " . + "[--show]\n"; + +BEGIN +{ + $| = 1; + print "\n"; +} + +#=============================================================================== +MAIN: +#=============================================================================== +{ + my $stones = $STONES; + my $jewels = $JEWELS; + my $show = 0; + + GetOptions + ( + 'stones=s' => \$stones, + 'jewels=s' => \$jewels, + 'show' => \$show, + + ) or die $USAGE; + + my $count = 0; + my %jewels = map { $_ => undef } grep { /$ALPHA/ } split //, $jewels; + + # Count each letter in the "stones" string if and only if it also occurs + # (anywhere, but at least once) in the "jewels" string + + my @letters if $show; + + for my $letter (grep { /$ALPHA/ } split //, $stones) + { + if (exists $jewels{$letter}) + { + ++$count ; + push(@letters, $letter) if $show; + } + } + + my $width = length $count; + + printf "%*d of the letters in the Stones string \"%s\"\n" . + "%*s also occur%s in the Jewels string \"%s\"\n", + $width, $count, $stones, + ($count == 1 ? $width - 1 : $width), '', + ($count == 1 ? 's' : '' ), $jewels; + + print('namely (', join(', ', @letters), ")\n") if $show; +} + +################################################################################ diff --git a/challenge-026/athanasius/perl5/ch-2.pl b/challenge-026/athanasius/perl5/ch-2.pl new file mode 100644 index 0000000000..4083d0ce86 --- /dev/null +++ b/challenge-026/athanasius/perl5/ch-2.pl @@ -0,0 +1,126 @@ +#!perl + +################################################################################ +=comment + +Perl Weekly Challenge 026 +========================= + +Task #2 +------- +Create a script that prints *mean angles* of the given list of angles in +degrees. Please read [ https://en.wikipedia.org/wiki/Mean_of_circular_quantities +|wiki page] that explains the formula in details with an example. + +=cut +################################################################################ + +#--------------------------------------# +# Copyright © 2019 PerlMonk Athanasius # +#--------------------------------------# + +use strict; +use warnings; +use utf8; +use Const::Fast; +use Data::Types qw( is_float ); +use Getopt::Long; + +const my $PI => 4 * atan2(1, 1); +const my $USAGE => + "USAGE:\n perl $0 [<angles> ...]\n" . + " perl $0 -- [<angles> ...] (to include +/- prefixes)\n" . + " perl $0 [--filename=<Str>]\n"; + +BEGIN +{ + $| = 1; + print "\n"; +} + +#=============================================================================== +MAIN: +#=============================================================================== +{ + # Parse the command line + + GetOptions('file=s' => \my $file) + or die $USAGE; + + defined $file && scalar @ARGV > 0 + and die "ERROR: Found filename as well as angle(s)\n$USAGE"; + + # Read and validate the input data + + my @angles = defined $file ? read_file($file) : @ARGV; + + scalar @angles > 0 + or die $USAGE; + + for my $angle (@angles) + { + is_float($angle) + or die "ERROR: Invalid angle \"$angle\"\n$USAGE"; + } + + # Calculate and display the circular mean + + printf "The circular mean of the angle%s\n (%s)\nis %s°\n", + scalar @angles == 1 ? '' : 's', + join(', ', map { "$_°" } @angles), + sprintf find_circular_mean(@angles); +} + +#------------------------------------------------------------------------------- +sub read_file +#------------------------------------------------------------------------------- +{ + my ($file) = @_; + my @angles; + + open my $fh, '<', $file + or die "Cannot open file \"$file\" for reading, stopped"; + + # File format: one angle (in degrees) per line; blank lines are ignored + + while (my $line = <$fh>) + { + $line =~ s/ ^ \s+ //x; # trim leading whitespace + $line =~ s/ \s+ $ //x; # trim trailing whitespace (including newline) + + next if $line eq ''; + + push @angles, $line; + } + + close $fh + or die "Cannot close file \"$file\", stopped"; + + return @angles; +} + +#------------------------------------------------------------------------------- +sub find_circular_mean +#------------------------------------------------------------------------------- +{ + # The circular mean (in radians) is given by the formula: + # + # atan2( 1/n ∑ [j=1..n] sin α_j, 1/n ∑ [j=1..n] cos α_j ) + + my @angles = @_; + my $sum_of_sines = 0; + my $sum_of_cosines = 0; + + for my $degrees (@angles) + { + my $radians = $degrees * ($PI / 180); + $sum_of_sines += sin $radians; # build ∑ [j=1..n] sin α_j + $sum_of_cosines += cos $radians; # build ∑ [j=1..n] cos α_j + } + + my $n = scalar @angles; + + return atan2($sum_of_sines / $n, $sum_of_cosines / $n) * (180 / $PI); +} + +################################################################################ diff --git a/challenge-026/athanasius/perl6/ch-1.p6 b/challenge-026/athanasius/perl6/ch-1.p6 new file mode 100644 index 0000000000..29f9663afb --- /dev/null +++ b/challenge-026/athanasius/perl6/ch-1.p6 @@ -0,0 +1,68 @@ +use v6; + +################################################################################ +=begin comment + +Perl Weekly Challenge 026 +========================= + +Task #1 +------- +Create a script that accepts two strings, let us call it, *"stones"* and +*"jewels"*. It should print the count of "alphabet" from the string *"stones"* +found in the string *"jewels"*. For example, if your *stones* is *"chancellor"* +and *"jewels"* is *"chocolate"*, then the script should print *"8"*. To keep it +simple, only A-Z,a-z characters are acceptable. Also make the comparison case +sensitive. + +=end comment +################################################################################ + +#--------------------------------------# +# Copyright © 2019 PerlMonk Athanasius # +#--------------------------------------# + +my Regex constant $ALPHA = rx{ <[A..Za..z]> }; +my Str constant $STONES = 'chancellor'; +my Str constant $JEWELS = 'chocolate'; + +BEGIN say ''; + +#=============================================================================== +sub MAIN +#=============================================================================== +( + Str:D :$stones = $STONES, #= The "stones" string + Str:D :$jewels = $JEWELS, #= The "jewels" string + Bool:D :$show = False, #= Show the matching letters? +) +{ + my UInt $count = 0; + my Nil %jewels = $jewels.split('').grep( { $ALPHA } ).map( { $_ => Nil } ); + + # Count each letter in the "stones" string if and only if it also occurs + # (anywhere, but at least once) in the "jewels" string + + my Str @letters if $show; + + for $stones.split('').grep( { $ALPHA } ) -> Str $letter + { + if %jewels{$letter}:exists + { + ++$count; + @letters.push($letter) if $show; + } + } + + my UInt $width = $count.chars; + + ("%*d of the letters in the Stones string \"%s\"\n" ~ + "%*s also occur%s in the Jewels string \"%s\"\n").printf: + $width, $count, $stones, + ($count == 1 ?? $width - 1 !! $width), '', + ($count == 1 ?? 's' !! '' ), $jewels; + + "namely ({ @letters.join(', ') })".say if $show && @letters.elems; +} + +################################################################################ diff --git a/challenge-026/athanasius/perl6/ch-2.p6 b/challenge-026/athanasius/perl6/ch-2.p6 new file mode 100644 index 0000000000..612b67c15a --- /dev/null +++ b/challenge-026/athanasius/perl6/ch-2.p6 @@ -0,0 +1,121 @@ +use v6; + +################################################################################ +=begin comment + +Perl Weekly Challenge 026 +========================= + +Task #2 +------- +Create a script that prints *mean angles* of the given list of angles in +degrees. Please read [ https://en.wikipedia.org/wiki/Mean_of_circular_quantities +|wiki page] that explains the formula in details with an example. + +=end comment +################################################################################ + +#--------------------------------------# +# Copyright © 2019 PerlMonk Athanasius # +#--------------------------------------# + +BEGIN say ''; + +#=============================================================================== +multi sub MAIN(Str:D :$file) #= Data file containing angles (degrees), + #= one per line +#=============================================================================== +{ + my Real @angles; + + for $file.IO.lines + { + my $line = $_; + + $line ~~ s/ ^^ \s+ //; + $line ~~ s/ \s+ $$ //; + + next unless $line.chars > 0; + + use fatal; + + @angles.push: val($line, :val-or-fail); + } + + MAIN(@angles); + + CATCH + { + when X::Str::Numeric + { + $*ERR.say: "In file \"$file\":\n{ .message }\n$*USAGE"; + } + } +} + +#------------------------------------------------------------------------------- +class X::Mean-Angles::No-Angles is Exception +#------------------------------------------------------------------------------- +{ + method message(--> Str:D) + { + return 'No angles found'; + } +} + +#=============================================================================== +multi sub MAIN(*@angles) #= One or more angles (all in degrees) +#=============================================================================== +{ + my Real:D @real-angles = @angles; + + @real-angles.elems > 0 + or X::Mean-Angles::No-Angles.new.throw; + + # Calculate and display the circular mean + + $*OUT.encoding('windows-1252'); + + "The circular mean of the angle%s\n (%s)\nis %.1f°\n".printf: + @angles.elems == 1 ?? '' !! 's', + @angles.map( { "$_°" } ).join(', '), + find-circular-mean(@angles); + + CATCH + { + when X::TypeCheck::Assignment + { + $*ERR.say: .message ~ "\n$*USAGE"; + } + + when X::Mean-Angles::No-Angles + { + $*ERR.say: .message ~ "\n$*USAGE"; + } + } +} + +#------------------------------------------------------------------------------- +sub find-circular-mean(*@angles --> Real:D) +#------------------------------------------------------------------------------- +{ + # The circular mean (in radians) is given by the formula: + # + # atan2( 1/n ∑ [j=1..n] sin α_j, 1/n ∑ [j=1..n] cos α_j ) + + my Real $sum-of-sines = 0; + my Real $sum-of-cosines = 0; + + for @angles -> Real $degrees + { + my Real $radians = $degrees * (π / 180); + $sum-of-sines += $radians.sin; # build ∑ [j=1..n] sin α_j + $sum-of-cosines += $radians.cos; # build ∑ [j=1..n] cos α_j + } + + my UInt $n = @angles.elems; + + return ($sum-of-sines / $n).atan2($sum-of-cosines / $n) * (180 / π); +} + +################################################################################ diff --git a/challenge-026/colin-crain/perl5/ch-1.pl b/challenge-026/colin-crain/perl5/ch-1.pl new file mode 100644 index 0000000000..8850b2c724 --- /dev/null +++ b/challenge-026/colin-crain/perl5/ch-1.pl @@ -0,0 +1,35 @@ +#! /opt/local/bin/perl +# +# stones_and_jewels.pl + |
