Playfair cipher: Difference between revisions
Content added Content deleted
(Added FreeBASIC) |
(Added Kotlin) |
||
Line 868: | Line 868: | ||
} |
} |
||
}</lang> |
}</lang> |
||
=={{header|Kotlin}}== |
|||
{{trans|FreeBASIC}} |
|||
<lang scala>// version 1.0.5-2 |
|||
enum class PlayfairOption { |
|||
NO_Q, |
|||
I_EQUALS_J |
|||
} |
|||
class Playfair(val keyword: String, val pfo: PlayfairOption) { |
|||
private val table: Array<CharArray> = Array(5, { CharArray(5) }) // 5 x 5 char array |
|||
init { |
|||
// build table |
|||
val used = BooleanArray(26) // all elements false |
|||
if (pfo == PlayfairOption.NO_Q) |
|||
used[16] = true // Q used |
|||
else |
|||
used[9] = true // J used |
|||
val alphabet = keyword.toUpperCase() + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
|||
var i = 0 |
|||
var j = 0 |
|||
var c: Char |
|||
var d: Int |
|||
for (k in 0 until alphabet.length) { |
|||
c = alphabet[k] |
|||
if (c !in 'A'..'Z') continue |
|||
d = c.toInt() - 65 |
|||
if (!used[d]) { |
|||
table[i][j] = c |
|||
used[d] = true |
|||
if (++j == 5) { |
|||
if (++i == 5) break // table has been filled |
|||
j = 0 |
|||
} |
|||
} |
|||
} |
|||
} |
|||
private fun getCleanText(plainText: String): String { |
|||
val plainText2 = plainText.toUpperCase() // ensure everything is upper case |
|||
// get rid of any non-letters and insert X between duplicate letters |
|||
var cleanText = "" |
|||
var prevChar = '\u0000' // safe to assume null character won't be present in plainText |
|||
var nextChar: Char |
|||
for (i in 0 until plainText2.length) { |
|||
nextChar = plainText2[i] |
|||
// It appears that Q should be omitted altogether if NO_Q option is specified - we assume so anyway |
|||
if (nextChar !in 'A'..'Z' || (nextChar == 'Q' && pfo == PlayfairOption.NO_Q)) continue |
|||
// If I_EQUALS_J option specified, replace J with I |
|||
if (nextChar == 'J' && pfo == PlayfairOption.I_EQUALS_J) nextChar = 'I' |
|||
if (nextChar != prevChar) |
|||
cleanText += nextChar |
|||
else |
|||
cleanText += "X" + nextChar |
|||
prevChar = nextChar |
|||
} |
|||
val len = cleanText.length |
|||
if (len % 2 == 1) { // dangling letter at end so add another letter to complete digram |
|||
if (cleanText[len - 1] != 'X') |
|||
cleanText += 'X' |
|||
else |
|||
cleanText += 'Z' |
|||
} |
|||
return cleanText |
|||
} |
|||
private fun findChar(c: Char): Pair<Int, Int> { |
|||
for (i in 0..4) |
|||
for (j in 0..4) |
|||
if (table[i][j] == c) return Pair(i, j) |
|||
return Pair(-1, -1) |
|||
} |
|||
public fun encode(plainText: String): String { |
|||
val cleanText = getCleanText(plainText) |
|||
var cipherText = "" |
|||
var length = cleanText.length |
|||
for (i in 0 until length step 2) { |
|||
val (row1, col1) = findChar(cleanText[i]) |
|||
val (row2, col2) = findChar(cleanText[i + 1]) |
|||
cipherText += when { |
|||
row1 == row2 -> table[row1][(col1 + 1) % 5].toString() + table[row2][(col2 + 1) % 5] |
|||
col1 == col2 -> table[(row1 + 1) % 5][col1].toString() + table[(row2 + 1) % 5][col2] |
|||
else -> table[row1][col2].toString() + table[row2][col1] |
|||
} |
|||
if (i < length - 1) cipherText += " " |
|||
} |
|||
return cipherText |
|||
} |
|||
public fun decode(cipherText: String): String { |
|||
var decodedText = "" |
|||
var length = cipherText.length |
|||
for (i in 0 until length step 3) { // cipherText will include spaces so we need to skip them |
|||
val (row1, col1) = findChar(cipherText[i]) |
|||
val (row2, col2) = findChar(cipherText[i + 1]) |
|||
decodedText += when { |
|||
row1 == row2 -> table[row1][if (col1 > 0) col1 - 1 else 4].toString() + table[row2][if (col2 > 0) col2 - 1 else 4] |
|||
col1 == col2 -> table[if (row1 > 0) row1- 1 else 4][col1].toString() + table[if (row2 > 0) row2 - 1 else 4][col2] |
|||
else -> table[row1][col2].toString() + table[row2][col1] |
|||
} |
|||
if (i < length - 1) decodedText += " " |
|||
} |
|||
return decodedText |
|||
} |
|||
public fun printTable() { |
|||
println("The table to be used is :\n") |
|||
for (i in 0..4) { |
|||
for (j in 0..4) print(table[i][j] + " ") |
|||
println() |
|||
} |
|||
} |
|||
} |
|||
fun main(args: Array<String>) { |
|||
print("Enter Playfair keyword : ") |
|||
val keyword: String = readLine()!! |
|||
var ignoreQ: String |
|||
do { |
|||
print("Ignore Q when buiding table y/n : ") |
|||
ignoreQ = readLine()!!.toLowerCase() |
|||
} |
|||
while (ignoreQ != "y" && ignoreQ != "n") |
|||
val pfo = if (ignoreQ == "y") PlayfairOption.NO_Q else PlayfairOption.I_EQUALS_J |
|||
val playfair = Playfair(keyword, pfo) |
|||
playfair.printTable() |
|||
print("\nEnter plain text : ") |
|||
val plainText: String = readLine()!! |
|||
val encodedText = playfair.encode(plainText) |
|||
println("\nEncoded text is : $encodedText") |
|||
val decodedText = playfair.decode(encodedText) |
|||
println("Decoded text is : $decodedText") |
|||
}</lang> |
|||
{{out}} |
|||
<pre> |
|||
Enter Playfair keyword : Playfair example |
|||
Ignore Q when buiding table y/n : n |
|||
The table to be used is : |
|||
P L A Y F |
|||
I R E X M |
|||
B C D G H |
|||
K N O Q S |
|||
T U V W Z |
|||
Enter plain text : Hide the gold...in the TREESTUMP!!!! |
|||
Encoded text is : BM OD ZB XD NA BE KU DM UI XM MO UV IF |
|||
Decoded text is : HI DE TH EG OL DI NT HE TR EX ES TU MP |
|||
</pre> |
|||
=={{header|NetRexx}}== |
=={{header|NetRexx}}== |