aboutsummaryrefslogtreecommitdiff
path: root/challenge-015
diff options
context:
space:
mode:
authorMohammad S Anwar <mohammad.anwar@yahoo.com>2019-07-14 07:10:07 +0100
committerMohammad S Anwar <mohammad.anwar@yahoo.com>2019-07-14 07:10:07 +0100
commitf9a095fa25cbdadf0548b73a4a8df0f89ee5e79b (patch)
treec697087e1701a13d904c5456f89b7bd4af5e6735 /challenge-015
parent6c8c0049d85d59297d0875b3cf614205d981c6d5 (diff)
downloadperlweeklychallenge-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/README1
-rw-r--r--challenge-015/michael-hamlin/perl5/GetPrime.pm48
-rw-r--r--challenge-015/michael-hamlin/perl5/Vignere.pm66
-rw-r--r--challenge-015/michael-hamlin/perl5/ch-1.pl28
-rw-r--r--challenge-015/michael-hamlin/perl5/ch-2.pl23
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";
+