135 lines
5 KiB
Text
135 lines
5 KiB
Text
import "./dynamic" for Enum
|
|
import "./str" for Str, Char
|
|
import "./iterate" for Stepped
|
|
import "./ioutil" for Input
|
|
|
|
var PlayfairOption = Enum.create("PlayfairOption", ["NO_Q", "I_EQUALS_J"])
|
|
|
|
class Playfair {
|
|
construct new(keyword, pfo) {
|
|
_pfo = pfo
|
|
// build_table
|
|
_table = List.filled(5, null)
|
|
for (i in 0..4) _table[i] = List.filled(5, "\0") // 5 * 5 char list
|
|
var used = List.filled(26, false)
|
|
if (_pfo == PlayfairOption.NO_Q) {
|
|
used[16] = true // Q used
|
|
} else {
|
|
used[9] = true // J used
|
|
}
|
|
var alphabet = Str.upper(keyword) + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
var i = 0
|
|
var j = 0
|
|
for (k in 0...alphabet.count) {
|
|
var c = alphabet[k]
|
|
if (Char.isAsciiUpper(c)) {
|
|
var d = c.bytes[0] - 65
|
|
if (!used[d]) {
|
|
_table[i][j] = c
|
|
used[d] = true
|
|
j = j + 1
|
|
if (j == 5) {
|
|
i = i + 1
|
|
if (i == 5) break // table has been filled
|
|
j = 0
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
getCleanText_(plainText) {
|
|
var plainText2 = Str.upper(plainText) // ensure everything is upper case
|
|
// get rid of any non-letters and insert X between duplicate letters
|
|
var cleanText = ""
|
|
var prevChar = "\0" // safe to assume null character won't be present in plainText
|
|
for (i in 0...plainText2.count) {
|
|
var nextChar = plainText2[i]
|
|
// It appears that Q should be omitted altogether if NO_Q option is specified - we assume so anyway
|
|
if (Char.isAsciiUpper(nextChar) && (nextChar != "Q" || _pfo != PlayfairOption.NO_Q)) {
|
|
// If I_EQUALS_J option specified, replace J with I
|
|
if (nextChar == "J" && _pfo == PlayfairOption.I_EQUALS_J) nextChar = "I"
|
|
if (nextChar != prevChar) {
|
|
cleanText = cleanText + nextChar
|
|
} else {
|
|
cleanText = cleanText + "X" + nextChar
|
|
}
|
|
prevChar = nextChar
|
|
}
|
|
}
|
|
var len = cleanText.count
|
|
if (len % 2 == 1) { // dangling letter at end so add another letter to complete digram
|
|
if (cleanText[-1] != "X") {
|
|
cleanText = cleanText + "X"
|
|
} else {
|
|
cleanText = cleanText + "Z"
|
|
}
|
|
}
|
|
return cleanText
|
|
}
|
|
|
|
findChar_(c) {
|
|
for (i in 0..4) {
|
|
for (j in 0..4) if (_table[i][j] == c) return [i, j]
|
|
}
|
|
return [-1, -1]
|
|
}
|
|
|
|
encode(plainText) {
|
|
var cleanText = getCleanText_(plainText)
|
|
var cipherText = ""
|
|
var length = cleanText.count
|
|
for (i in Stepped.new(0...length, 2)) {
|
|
var pair = findChar_(cleanText[i])
|
|
var row1 = pair[0]
|
|
var col1 = pair[1]
|
|
pair = findChar_(cleanText[i + 1])
|
|
var row2 = pair[0]
|
|
var col2 = pair[1]
|
|
cipherText = cipherText +
|
|
((row1 == row2) ? _table[row1][(col1 + 1) % 5] +_table[row2][(col2 + 1) % 5] :
|
|
(col1 == col2) ? _table[(row1 + 1) % 5][col1] +_table[(row2 + 1) % 5][col2] :
|
|
_table[row1][col2] +_table[row2][col1])
|
|
if (i < length - 1) cipherText = cipherText + " "
|
|
}
|
|
return cipherText
|
|
}
|
|
|
|
decode(cipherText) {
|
|
var decodedText = ""
|
|
var length = cipherText.count
|
|
for (i in Stepped.new(0...length, 3)) { // cipherText will include spaces so we need to skip them
|
|
var pair = findChar_(cipherText[i])
|
|
var row1 = pair[0]
|
|
var col1 = pair[1]
|
|
pair = findChar_(cipherText[i + 1])
|
|
var row2 = pair[0]
|
|
var col2 = pair[1]
|
|
decodedText = decodedText +
|
|
((row1 == row2) ? _table[row1][(col1 > 0) ? col1-1 : 4] +_table[row2][(col2 > 0) ? col2-1 : 4] :
|
|
(col1 == col2) ? _table[(row1 > 0) ? row1-1 : 4][col1] +_table[(row2 > 0) ? row2-1 : 4][col2] :
|
|
_table[row1][col2] +_table[row2][col1])
|
|
if (i < length - 1) decodedText = decodedText + " "
|
|
}
|
|
return decodedText
|
|
}
|
|
|
|
printTable() {
|
|
System.print("The_table to be used is :\n")
|
|
for (i in 0..4) {
|
|
for (j in 0..4) System.write(_table[i][j] + " ")
|
|
System.print()
|
|
}
|
|
}
|
|
}
|
|
|
|
var keyword = Input.text("Enter Playfair keyword : ", 1)
|
|
var ignoreQ = Str.lower(Input.option("Ignore Q when building_table y/n : ", "yYnN"))
|
|
var pfo = (ignoreQ == "y") ? PlayfairOption.NO_Q : PlayfairOption.I_EQUALS_J
|
|
var playfair = Playfair.new(keyword, pfo)
|
|
playfair.printTable()
|
|
var plainText = Input.text("\nEnter plain text : ")
|
|
var encodedText = playfair.encode(plainText)
|
|
System.print("\nEncoded text is : %(encodedText)")
|
|
var decodedText = playfair.decode(encodedText)
|
|
System.print("Decoded text is : %(decodedText)")
|