aboutsummaryrefslogtreecommitdiff
path: root/challenge-035/mark-senn/perl6/ch-2.p6
blob: 8867616835bdf02a507562a072ba51df7f7aceec (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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#
# Perl Weekly Challenge - 035
# Task #1 and #2
# 
#
# Mark Senn, http://engineering.purdue.edu/~mark
# November 24, 2019
#
# From
# https://perlweeklychallenge.org/blog/perl-weekly-challenge-035#task-1
#     Contributed by Paul Johnson
#     Write a program to encode text into binary encoded morse code.
#
#     Pay attention to any changes which might need to be made to the
#     text to make it valid morse code.
#
#     Morse code (see https://en.wikipedia.org/wiki/Morse_code)
#     consists of dots, dashes and gaps. It can be encoded in binary
#     in the following fashion:
#         dot: 1
#         dash: 111
#         intra-character gap: 0
#         character gap: 000
#         word gap: 0000000
#
#     An intra-character gap is inserted between the dots and dashes
#     in a character.
#
# This program converts text (variable name $plaintext) into binary
# encoded Morse code (variable name $ciphertext).
#

# Run using Raku v6.d;
use v6.d;

# Read the input from the command line.  If no input is given
# use the string "42 db".
my $plaintext = '42 db';
@*ARGS.elems  and  $plaintext = "{@*ARGS}";

# Based on information in
#     https://en.wikipedia.org/wiki/File:International_Morse_Code.svg
# I put a space between all dots and/or dashes to improve readability.
# This program only supports lowercase letters and digits.  Add more
# plaintext symbols here if you'd like.
my %plain2cipher =
    a => '. -',          b => '- . . .',      c => '- . - .',
    d => '- . .',        e => '.',            f => '. . - .',
    g => '- - .',        h => '. . . .',      i => '. .',
    j => '. - - -',      k => '- . -',        l => '. - . .',
    m => '- -',          n => '- .',          o => '- - -',
    p => '. - - .',      q => '- - . -',      r => '. - .',
    s => '. . .',        t => '-',            u => '. . -',
    v => '. . . -',      w => '. - -',        x => '- . . -',
    y => '- . - -',      z => '- - . .',      1 => '. - - - -',
    2 => '. . - - -',    3 => '. . . - -',    4 => '. . . . -',
    5 => '. . . . .',    6 => '- . . . .',    7 => '- - . . .',
    8 => '- - - . .',    9 => '- - - - .',    0 => '- - - - -';

# Replace %plain2cipher values with corresponding binary values.
for %plain2cipher.values -> $_ is rw  {
    s:g/'.'/1/;    # dot
    s:g/'-'/111/;  # dash
    s:g/' '/0/;    # intra-character gap
}

# Compute %cipher2plain from %plain2cipher.
my %cipher2plain = %plain2cipher.invert;


#
#  Convert plaintext to ciphertext.
#

"plaintext:  $plaintext".say;

# Replace character gap and word gap with out-of-band characters---if they
# were expanded to their binary values here they could interfere with
# with $plaintext data.
$_ = $plaintext;
my $cgoob = '!';  # character gap
my $wgoob = '@';  # word gap
s:g/(\S)<before \S>/$0$cgoob/;  # character gap
s:g/' '/$wgoob/;                # word gap

# Replace in-band characters in $_ with their binary equivalents.
my $ciphertext = '';
for .comb(/./)  {
    %plain2cipher{$_}:exists
    ??  ($ciphertext ~= %plain2cipher{$_})
    !!  ($ciphertext ~= $_);
}

# Replace the out-of-band characters with their binary equivalents
$ciphertext ~~ s:g/$cgoob/000/;
$ciphertext ~~ s:g/$wgoob/0000000/;

"ciphertext: $ciphertext".say;


#
#  Convert ciphertext to plaintext.
#

$_ = $ciphertext;
$plaintext = '';
my @word = .split(/0000000/);  # word gap
loop (my $i = 0;  $i < @word.elems;  $i++)  {
    $_ = @word[$i];
    my @char = .split(/000/);  # character gap
    for (@char)  {
        $plaintext ~= %cipher2plain{$_};
    }
    ($i < @word.elems - 1)  and  $plaintext ~= ' ';
}

"plaintext:  $plaintext".say;