diff options
| author | Mohammad S Anwar <mohammad.anwar@yahoo.com> | 2019-07-14 07:10:07 +0100 |
|---|---|---|
| committer | Mohammad S Anwar <mohammad.anwar@yahoo.com> | 2019-07-14 07:10:07 +0100 |
| commit | f9a095fa25cbdadf0548b73a4a8df0f89ee5e79b (patch) | |
| tree | c697087e1701a13d904c5456f89b7bd4af5e6735 /challenge-015 | |
| parent | 6c8c0049d85d59297d0875b3cf614205d981c6d5 (diff) | |
| download | perlweeklychallenge-club-f9a095fa25cbdadf0548b73a4a8df0f89ee5e79b.tar.gz perlweeklychallenge-club-f9a095fa25cbdadf0548b73a4a8df0f89ee5e79b.tar.bz2 perlweeklychallenge-club-f9a095fa25cbdadf0548b73a4a8df0f89ee5e79b.zip | |
- Added solutions by Michael Hamlin.
Diffstat (limited to 'challenge-015')
| -rw-r--r-- | challenge-015/michael-hamlin/README | 1 | ||||
| -rw-r--r-- | challenge-015/michael-hamlin/perl5/GetPrime.pm | 48 | ||||
| -rw-r--r-- | challenge-015/michael-hamlin/perl5/Vignere.pm | 66 | ||||
| -rw-r--r-- | challenge-015/michael-hamlin/perl5/ch-1.pl | 28 | ||||
| -rw-r--r-- | challenge-015/michael-hamlin/perl5/ch-2.pl | 23 |
5 files changed, 166 insertions, 0 deletions
diff --git a/challenge-015/michael-hamlin/README b/challenge-015/michael-hamlin/README new file mode 100644 index 0000000000..4314e219f4 --- /dev/null +++ b/challenge-015/michael-hamlin/README @@ -0,0 +1 @@ +Solutions by Michael Hamlin. diff --git a/challenge-015/michael-hamlin/perl5/GetPrime.pm b/challenge-015/michael-hamlin/perl5/GetPrime.pm new file mode 100644 index 0000000000..17559ce4ea --- /dev/null +++ b/challenge-015/michael-hamlin/perl5/GetPrime.pm @@ -0,0 +1,48 @@ +#! /usr/bin/env perl + +# find primes (sort-of) efficiently (without a sieve) +# for an exercise without using cpan... + +package GetPrime; + +use 5.18.0; +use parent 'Exporter'; +our @EXPORT = qw<getprime>; + +use integer; + +my @primes = (2, 3, 5); +sub getprime ($) { + my $n = shift || die "must give an ordinal number to getprime"; + push @primes, _nextprime() while @primes < $n; + return $primes[$n - 1]; +} + +sub _nextprime { + my $n; + for ($n = $primes[-1] + 2; _hasfactor($n); $n += 2) { } + return $n; +} +sub _hasfactor { + my ($n) = @_; + # dont bother testing when ending in 5... + return 5 if $n =~ /5$/; + # we only get odds, so we dont need... + # return 2 if $n =~ /[02468]$/; + + my $maxfactor = sqrt($n); + foreach my $p (@primes) { + return $p unless $n % $p; + last if $p >= $maxfactor; + } + return 0; +} + +1; + +__END__ +#foreach (1..20) { +# printf "%2u: %u\n", $_, getprime($_); +#} +say 'the hundredth prime is ', getprime(100); + diff --git a/challenge-015/michael-hamlin/perl5/Vignere.pm b/challenge-015/michael-hamlin/perl5/Vignere.pm new file mode 100644 index 0000000000..494c322f5a --- /dev/null +++ b/challenge-015/michael-hamlin/perl5/Vignere.pm @@ -0,0 +1,66 @@ +package Vigenere; + +# implement the cipher of the same name. + +use 5.18.0; +use parent 'Exporter'; +our @EXPORT = qw<vencode vdecode>; + +use integer; +use List::SomeUtils qw<pairwise>; + +my $basis = join '', 'A' .. 'Z'; +my $blength = length $basis; + +our $debug = 0; + +sub _normalize { + return unless my $plaintext = uc(shift); + $plaintext =~ tr/A-Z//cd; + return $plaintext; +} +sub _ordify { + return map {ord($_) - 65} split //, shift; +} +sub _stringify { + return join '', map {chr($_ + 65)} @_; +} +sub _keyshifts { + my ($key, $len) = @_; + my @rots = _ordify($key); + push @rots, @rots while @rots < $len; + splice(@rots, $len); + return @rots; +} + + +sub vencode ($@) { + my $msg = _normalize(shift) || die "cipher can only encode ascii letters"; + while (my $key = _normalize(shift)) { + say "key: [$key]" if $debug; + my @mchars = _ordify($msg); + my @rots = _keyshifts($key, length($msg)); + my @res = pairwise {($a + $b) % $blength} @mchars, @rots; + $msg = _stringify(@res); + if ($debug) { + say "msg @mchars"; + say "rot @rots"; + say "res @res"; + } + } + return $msg; +} + +sub vdecode ($@) { + my $msg = shift; + die "some chars in ciphertext cannot have been encoded" if $msg =~ tr/A-Z/ /c; + while (my $key = _normalize(shift)) { + my @mchars = _ordify($msg); + my @rots = _keyshifts($key, length($msg)); + my @res = pairwise {($blength + $a - $b) % $blength} @mchars, @rots; + $msg = _stringify(@res); + } + return $msg; +} +1; + diff --git a/challenge-015/michael-hamlin/perl5/ch-1.pl b/challenge-015/michael-hamlin/perl5/ch-1.pl new file mode 100644 index 0000000000..bbbf14099c --- /dev/null +++ b/challenge-015/michael-hamlin/perl5/ch-1.pl @@ -0,0 +1,28 @@ +#! /usr/bin/env perl + +use 5.18.0; +use GetPrime; +use integer; + +my $n = shift @ARGV || 10; + +my (@strong, @weak); + +for (my $i = 2; @strong < $n && @weak < $n; $i++) { + my $prime = getprime($i); + # avoiding division for speed + + my $doubled = 2 * $prime; # saves an op later + my $neighbor_sum = getprime($i-1) + getprime($i+1); + + if ($doubled > $neighbor_sum) { + push @strong, $prime; + } elsif ($doubled < $neighbor_sum) { + push @weak, $prime; + } else { + say "zomg prime #$i ($prime) is neither!" +} +} + +say "Strongs are: @strong"; +say "Weaks are: @weak"; diff --git a/challenge-015/michael-hamlin/perl5/ch-2.pl b/challenge-015/michael-hamlin/perl5/ch-2.pl new file mode 100644 index 0000000000..9d30e5e5a1 --- /dev/null +++ b/challenge-015/michael-hamlin/perl5/ch-2.pl @@ -0,0 +1,23 @@ +#! /usr/bin/env perl + +use 5.18.0; +use Vigenere; + +use Getopt::Long; + +my %opt; +GetOptions(\%opt, + 'key|k=s@', + 'msg|m=s', +); + +my $plaintext = $opt{msg} || 'attack at dawn'; +my @keys = $opt{key} ? @{ $opt{key} } : 'lemon'; + +my $cipher = vencode($plaintext, @keys); +my $decoded = vdecode($cipher, reverse @key +s); + +print "ciphertext: $cipher\n"; +print "decoded: $decoded\n"; + |
