diff options
| -rw-r--r-- | challenge-015/dave-jacoby/perl5/ch-1.pl | 78 | ||||
| -rw-r--r-- | challenge-015/dave-jacoby/perl5/ch-2.pl | 101 |
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; +} |
