I think the table should be an result of the shifting alphabet concept! I do like the idea of being more robust to input strings.
Here’s version 2:
number(letter) = letter-'A' # number of letters between `letter` and 'A'
letter(number) = 'A'+(number+26)%26 # the `number`th letter after 'A' (negative `number` means it should be before 'A')
# Loop around if you run out of letters in the alphabet. So "A-1=Z" and "A+27=B".
→(a::Char,b::Char) = letter(number(a)+number(b)) # encode using +
←(a::Char,b::Char) = letter(number(a)-number(b)) # decode using -
isletter(a) = a in 'A':'Z' # is `a` inside the letters from 'A' to 'Z'?
cleanup(str::String) = filter(isletter, collect(uppercase.(str))) # make all letters uppercase and filter out non-letters
match_length(word,len) = repeat(word,len)[1:len] # repeat the codeword until you match the length
function →(message::String,codeword::String, ↔ = →)
plaintext = cleanup(message)
key = match_length(cleanup(codeword),length(plaintext))
return String(plaintext .↔ key)
end
←(message::String,codeword::String) = →(message,codeword,←)
Trying to slow down a little and add comments to help her (she’s 12 and hasn’t taken any coding yet).
julia> number('A'),number('L')
(0, 11)
julia> letter(2),letter(-2)
('C', 'Y')
julia> alpha = 'A':'Z';
julia> alpha .→ permutedims(alpha)
26×26 Matrix{Char}:
'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'
'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' 'A'
'C' 'D' 'E' 'F' 'G' 'H' 'I' 'J' 'K' 'L' 'M' 'N' 'O' 'P' 'Q' 'R' 'S' 'T' 'U' 'V' 'W' 'X' 'Y' 'Z' 'A' 'B'
'D' 'E' 'F' 'G' 'H' 'I' 'J' 'K' 'L' 'M' 'N' 'O' 'P' 'Q' 'R' 'S' 'T' 'U' 'V' 'W' 'X' 'Y' 'Z' 'A' 'B' 'C'
⋮ ⋮ ⋮ ⋮ ⋮ ⋮
'W' 'X' 'Y' 'Z' 'A' 'B' 'C' 'D' 'E' 'F' 'G' 'H' 'I' 'J' 'K' 'L' 'M' 'N' 'O' 'P' 'Q' 'R' 'S' 'T' 'U' 'V'
'X' 'Y' 'Z' 'A' 'B' 'C' 'D' 'E' 'F' 'G' 'H' 'I' 'J' 'K' 'L' 'M' 'N' 'O' 'P' 'Q' 'R' 'S' 'T' 'U' 'V' 'W'
'Y' 'Z' 'A' 'B' 'C' 'D' 'E' 'F' 'G' 'H' 'I' 'J' 'K' 'L' 'M' 'N' 'O' 'P' 'Q' 'R' 'S' 'T' 'U' 'V' 'W' 'X'
'Z' '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'
julia> cleanup("a & b & z")
3-element Vector{Char}:
'A': ASCII/Unicode U+0041 (category Lu: Letter, uppercase)
'B': ASCII/Unicode U+0042 (category Lu: Letter, uppercase)
'Z': ASCII/Unicode U+005A (category Lu: Letter, uppercase)
julia> match_length("funrun",10)
"funrunfunr"
julia> cyphertext = "I want spearmint gum" → "Gimme!"
"OEMZXYXQMVSQZFKAU"
julia> cyphertext ← "Gimme!"
"IWANTSPEARMINTGUM"