aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--challenge-015/dave-jacoby/perl5/ch-1.pl78
-rw-r--r--challenge-015/dave-jacoby/perl5/ch-2.pl101
2 files changed, 179 insertions, 0 deletions
diff --git a/challenge-015/dave-jacoby/perl5/ch-1.pl b/challenge-015/dave-jacoby/perl5/ch-1.pl
new file mode 100644
index 0000000000..4c66702a02
--- /dev/null
+++ b/challenge-015/dave-jacoby/perl5/ch-1.pl
@@ -0,0 +1,78 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+use feature qw{ postderef say signatures state };
+no warnings qw{ experimental::postderef experimental::signatures };
+
+# Write a script to generate first 10 strong and weak prime numbers.
+
+# https://en.wikipedia.org/wiki/Strong_prime
+# (which contains a list of strong primes to ensure things are correct)
+
+# For example, the nth prime number is represented by p(n).
+
+# p(1) = 2
+# p(2) = 3
+# p(3) = 5
+# p(4) = 7
+# p(5) = 11
+
+# Strong Prime number p(n) when p(n) > [ p(n-1) + p(n+1) ] / 2
+# Weak Prime number p(n) when p(n) < [ p(n-1) + p(n+1) ] / 2
+
+my @primes;
+my @strong;
+my @weak;
+
+# create list of primes to judge strong, weak or balanced
+while ( @strong < 10 && @weak < 10 ) {
+ state $c += 1;
+ if ( is_prime($c) ) { push @primes, $c }
+ last if scalar @primes > 100;
+}
+
+for my $n ( 1 .. @primes ) {
+ my $swb = is_strong($n);
+ my $o = $primes[$n];
+ push @strong, $o if $swb == 1;
+ push @weak, $o if $swb == -1;
+ last if @weak > 10 && @strong > 10;
+ say $swb;
+}
+say 'strong: ' . join ", ", @strong[0..9];
+say 'weak: ' . join ", ", @weak[0..9];
+exit;
+
+# Strong Prime number p(n) when p(n) > [ p(n-1) + p(n+1) ] / 2
+# Weak Prime number p(n) when p(n) < [ p(n-1) + p(n+1) ] / 2
+
+# 1 if strong
+# -1 if weak
+# 0 if balanced
+sub is_strong ( $n ) {
+ my $o = $primes[$n];
+ return 3 if $n <= 0; # no n-1 -- look up this special case
+ return 4
+ if !$primes[ $n + 1 ]; # no n+1 -- we should be done well before then
+ my $p = ( $primes[ $n - 1 ] + $primes[ $n + 1 ] ) / 2;
+ return 1 if $o > $p;
+ return -1 if $o < $p;
+ return 0;
+}
+
+# this one again
+sub is_prime ( $n ) {
+ my @factors = factor($n);
+ return scalar @factors == 1 ? 1 : 0;
+}
+
+# this has a slight modification, going only to sqrt $n, because
+# there can't be a factor above that. Duh.
+sub factor ( $n ) {
+ my @factors;
+ for my $i ( 1 .. sqrt $n ) {
+ push @factors, $i if $n % $i == 0;
+ }
+ return @factors;
+}
diff --git a/challenge-015/dave-jacoby/perl5/ch-2.pl b/challenge-015/dave-jacoby/perl5/ch-2.pl
new file mode 100644
index 0000000000..5dd4ca6076
--- /dev/null
+++ b/challenge-015/dave-jacoby/perl5/ch-2.pl
@@ -0,0 +1,101 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+use feature qw{ postderef say signatures state fc };
+no warnings qw{ experimental::postderef experimental::signatures };
+
+my $keyword = 'ATTACKATDAWN';
+my $cleartext = <<'END';
+Write a script to implement Vigenere cipher.
+The script should be able encode and decode.
+END
+
+# the point ISN'T to show off Getopt or File I/O techniques
+# so I'm going way simple here.
+$keyword = $ARGV[0] ? $ARGV[0] : $keyword;
+$cleartext = $ARGV[1] ? $ARGV[1] : $cleartext;
+
+$keyword =~ tr/a-z/A-Z/;
+$keyword =~ s/\W//g;
+$cleartext =~ tr/a-z/A-Z/; # or uc $cleartext. TMTOWTDI
+$cleartext =~ s/\W//g; # text that isn't alpha isn't encrypted
+ # and can give the game away.
+
+my $cyphertext = encode_vigenere( $keyword, $cleartext );
+my $decrypt = decode_vigenere( $keyword, $cyphertext );
+say <<"END";
+ CLEAR:
+ $cleartext
+ CYPHER:
+ $cyphertext
+ DECRYPT:
+ $decrypt
+END
+exit;
+
+sub encode_vigenere ( $keyword, $cleartext ) {
+ my @keyword = split m{}, $keyword;
+ my @base = make_core_cypher();
+ my @alpha = 'A' .. 'Z';
+ my %alpha = map { $alpha[$_] => $_ } 0 .. 25;
+ my @cypher;
+ for my $clear ( split m{}, $cleartext ) {
+ state $c = 0;
+ # here's where I made a mistake, and wrote my decode to
+ # work with my mistake. I was using $c % length $keyword
+ # as the column determiner, rather than the index of the
+ # letter at position $c % length $keyword.
+ # the keyword 'aaaa' should give a cyphertext that's the
+ # same as the cleartext.
+
+ # If your algorithm cannot return an encrypted letter
+ # that's the same as the clear letter, you have an
+ # attack vector, but if your keyword is all "a" with this,
+ # you have not encrypted anything.
+
+ # and, really, long-term viability is not helped by
+ # short variable names
+ my $k = $keyword[ $c % length $keyword ];
+ my $d = $alpha{$k};
+ my $e = $alpha{$clear};
+ my $f = $base[$d][$e];
+ push @cypher, $f;
+ $c++;
+ }
+ return join '', @cypher;
+}
+
+sub decode_vigenere ( $keyword, $cyphertext ) {
+ my @keyword = split m{}, $keyword;
+ my @base = make_core_cypher();
+ my @alpha = 'A' .. 'Z';
+ my %alpha = map { $alpha[$_] => $_ } 0 .. 25;
+ my @clear;
+ for my $cypher ( split m{}, $cyphertext ) {
+ state $c = 0;
+ my $k = $keyword[ $c % length $keyword ];
+ my $d = $alpha{$k};
+ my $e;
+ for my $i ( 0 .. 25 ) {
+ $e = $i if $base[$d][$i] eq $cypher;
+ }
+ my $f = $alpha[$e];
+ push @clear, $f;
+ $c++;
+ }
+ return join '', @clear;
+}
+
+sub make_core_cypher () {
+ my @alpha = 'A' .. 'Z';
+ my @output;
+ for my $i ( 0 .. 25 ) {
+ for my $j ( 0 .. 25 ) {
+ my $k = ( $i + $j ) % 26;
+ my $l = $alpha[$k];
+ $output[$i][$j] = $l;
+ }
+ }
+ return @output;
+}