aboutsummaryrefslogtreecommitdiff
path: root/challenge-015/andrezgz/perl5/ch-2.pl
blob: c75919deec0378d8e819fe06a7cf9604c1533a0d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#!/usr/bin/perl

# https://perlweeklychallenge.org/blog/perl-weekly-challenge-015/
# Challenge #2
# Write a script to implement Vigen�re cipher.
# The script should be able encode and decode.
# Checkout wiki page for more information.
# https://en.wikipedia.org/wiki/Vigen%C3%A8re_cipher

use strict;
use warnings;

die "Usage: $0 <-e plaintext|-d ciphertext> <key>" unless (@ARGV == 3);

my $action = $ARGV[0];
if ($action eq '-e') {
    print encode($ARGV[1],$ARGV[2]);
}
elsif ($action eq '-d') {
    print decode($ARGV[1],$ARGV[2]);
}
else {
    print "Valid actions are: -e (encode) or -d (decode)\n";
}

sub encode { vigenere(@_, 1)  }
sub decode { vigenere(@_,-1) }

sub vigenere {
    my $text = clean(shift);
    my $key  = clean(shift);
    my $sign = shift;

    my $repeat = int(length($text)/length($key))+1;
    my $keyext = $key x $repeat; # repeat key string up to text length

    my @letters = 'A' .. 'Z';
    my %charcode = map { $letters[$_] => $_ } 0 .. 25;

    my $plain = '';
    foreach my $i (0 .. length($text)-1) {
        # the magic begins: Vigen�re algebraically applied
        $plain .= $letters[
                    ( $charcode{substr($text,$i,1)}
                      + $sign * $charcode{substr($keyext,$i,1)}
                    ) % 26
                  ];
    }
    return $plain;
}

sub clean {
    my $text = shift;
    $text =~ s/[^a-z]//gi;  # remove non-alphabetic characters
    return (uc $text);      # uppercase characters
}