Playfair cipher: Difference between revisions

m
(→‎{{header|REXX}}: extended the REXX pgm to allow a multi-word cipher (which necessitated changing the order of the 1st two variables). -- ~~~~)
m (→‎{{header|Wren}}: Minor tidy)
 
(96 intermediate revisions by 27 users not shown)
Line 1:
[[Category:Encryption]]
{{draft task}}
 
Implement a [[wp: Playfair cipher| Playfair cipher]] encryption and decryption.
{{task}}
 
;Task:
Implement a [[wp: Playfair cipher| Playfair cipher]] for encryption and decryption.
 
 
The user must be able to choose   '''J'''  =  '''I'''     or   no   '''Q'''   in the alphabet.
 
The user must be able to choose J = I or no Q in the alphabet.
The output of the encrypted and decrypted message must be in capitalized digraphs, separated by spaces.
 
 
Output example: HI DE TH EG OL DI NT HE TR EX ES TU MP.
;Output example:
HI DE TH EG OL DI NT HE TR EX ES TU MP
<br><br>
 
=={{header|11l}}==
{{trans|Python}}
 
<syntaxhighlight lang="11l">F uniq(seq)
[Char] seen
L(x) seq
I x !C seen
seen.append(x)
R seen
 
F partition(seq, n)
R (0 .< seq.len).step(n).map(i -> @seq[i .< i + @n])
 
F canonicalize(s)
R s.uppercase().filter(c -> c.is_uppercase()).join(‘’).replace(‘J’, ‘I’)
 
T Playfair
[String = String] dec, enc
 
F (key)
V m = partition(uniq(canonicalize(key‘ABCDEFGHIJKLMNOPQRSTUVWXYZ’)), 5)
 
L(row) m
L(i, j) cart_product(0.<5, 0.<5)
I i != j
.enc[row[i]‘’row[j]] = row[(i + 1) % 5]‘’row[(j + 1) % 5]
 
L(ci) 5
V c = [m[0][ci], m[1][ci], m[2][ci], m[3][ci], m[4][ci]]
L(i, j) cart_product(0.<5, 0.<5)
I i != j
.enc[c[i]‘’c[j]] = c[(i + 1) % 5]‘’c[(j + 1) % 5]
 
L(i1, j1, i2, j2) cart_product(0.<5, 0.<5, 0.<5, 0.<5)
I i1 != i2 & j1 != j2
.enc[m[i1][j1]‘’m[i2][j2]] = m[i1][j2]‘’m[i2][j1]
 
.dec = Dict(.enc.map((k, v) -> (v, k)))
 
F encode(txt)
V c = canonicalize(txt)
[String] lst
V i = 0
L i < c.len - 1
I c[i + 1] == c[i]
lst [+]= c[i]‘X’
i++
E
lst [+]= c[i]‘’c[i + 1]
i += 2
I i == c.len - 1
lst [+]= c.last‘X’
R lst.map(a -> @.enc[a]).join(‘ ’)
 
F decode(encoded)
R partition(canonicalize(encoded), 2).map(p -> @.dec[p]).join(‘ ’)
 
V playfair = Playfair(‘Playfair example’)
V orig = ‘Hide the gold in...the TREESTUMP!!!’
print(‘Original: ’orig)
V enc = playfair.encode(orig)
print(‘Encoded: ’enc)
print(‘Decoded: ’playfair.decode(enc))</syntaxhighlight>
 
{{out}}
<pre>
Original: Hide the gold in...the TREESTUMP!!!
Encoded: BM OD ZB XD NA BE KU DM UI XM MO UV IF
Decoded: HI DE TH EG OL DI NT HE TR EX ES TU MP
</pre>
 
=={{header|APL}}==
{{works with|Dyalog APL}}
<syntaxhighlight lang="apl">⍝⍝⍝⍝ Utility functions
 
⍝ convert to uppercase
UpCase ← { 1 ⎕C ⍵ }
 
⍝ remove non-letters
JustLetters ← { ⍵ /⍨ ⍵∊⎕A }
 
⍝ replace 'J's with 'I's
ReplaceJ ← { ('J' ⎕R 'I') ⍵ }
 
⍝ Insert an 'X' between repeated letters
SplitDouble ← { (' '⎕R'X') ⍵ \⍨ 1,~⍵=1⌽⍵ }
 
⍝ Append an 'X' if the message is not of even length
PadEven ← { ⍵,(2|≢⍵) ⍴ 'X' }
 
⍝ Split text up into letter pairs
Pairs ← { (1=2|⍳≢⍵) ⊂ ∊ ⍵ }
 
⍝ Group text into chunks of five letters
Groups ← { (1=5|⍳≢⍵) ⊂ ∊ ⍵ }
 
⍝ Shift within 1-5 based on left arg (0 for +1,1 for -1)
Shift ← { ⍺ ← 0 ⋄ 1+5|(⍺+1)⌷⍵,3+⍵ }
 
⍝⍝⍝⍝ Playfair implementation
 
⍝ All the things we have to do to the plaintext, chained together
PreparePlaintext ← { PadEven SplitDouble ReplaceJ JustLetters UpCase ∊ ⍵ }
 
⍝ Ditto for ciphertext
PrepareCiphertext ← { JustLetters UpCase ∊ ⍵ }
 
⍝ Create the grid from the key
PrepareKey ← { 5 5⍴ ∪ ReplaceJ (JustLetters UpCase ⍵),⎕A }
 
⍝ Encode or decode a single pair of letters
∇resultPair ← grid TransformPair args;mode;inPair;l;r;i1;j1;i2;j2
mode inPair ← args
l r ← inPair
i1 j1 ← ⊃⍸grid=l
i2 j2 ← ⊃⍸grid=r
:If i1=i2
j1 ← mode Shift j1
j2 ← mode Shift j2
:Else
:If j1=j2
i1 ← mode Shift i1
i2 ← mode Shift i2
:Else
j1 j2 ← j2 j1
:EndIf
:EndIf
resultPair ← grid[(i1 j1)(i2 j2)]
 
⍝ Encode or decode an entire message
∇resultText ← grid TransformText args; mode; inText
mode inText ← args
resultText ← Groups ∊ { grid TransformPair mode ⍵ } ¨ Pairs inText
 
⍝ Specific transforms for each direction including key and text preparation
∇cipher ← key EncodeText plain
cipher ← (PrepareKey key) TransformText 0 (PreparePlaintext plain)
 
∇plain ← key DecodeText cipher
plain ← (PrepareKey key) TransformText 1 (PrepareCiphertext cipher)
 
⍝ Demo
key ← 'Playfair example'
plain ← 'Hide the gold in the tree stump.'
⎕ ← cipher ← key EncodeText plain
⎕ ← key DecodeText cipher</syntaxhighlight>
 
{{Out}}<pre> ⎕ ← cipher ← key EncodeText plain
┌─────┬─────┬─────┬─────┬─────┬─┐
│BMODZ│BXDNA│BEKUD│MUIXM│MOUVI│F│
└─────┴─────┴─────┴─────┴─────┴─┘
</pre>
<pre> ⎕ ← key DecodeText cipher
┌─────┬─────┬─────┬─────┬─────┬─┐
│HIDET│HEGOL│DINTH│ETREX│ESTUM│P│
└─────┴─────┴─────┴─────┴─────┴─┘
</pre>
 
=={{header|C++}}==
<langsyntaxhighlight lang="cpp">#include <iostream>
#include <string>
 
Line 117 ⟶ 288:
cout << "Enter the text: "; getline( cin, txt );
playfair pf; pf.doIt( key, txt, ij, e ); return system( "pause" );
}</langsyntaxhighlight>
{{out}}<pre>
(E)ncode or (D)ecode? e
Line 141 ⟶ 312:
=={{header|D}}==
{{trans|Python}}
<langsyntaxhighlight lang="d">import std.stdio, std.array, std.algorithm, std.range, std.ascii,
std.conv, std.string, std.regex, std.typecons;
 
string unique(in string s) pure /*nothrow*/ @safe {
string result;
foreach (immutable char c; s)
if (!result.representation.canFind(c)) // Assumes ASCII string.
result ~= c;
return result;
Line 156 ⟶ 327:
string[string] enc, dec;
 
this(in string key, in string from_ = "J", in string to_ = null) {
pure /*nothrow @safe*/ {
this.from = from_;
if (to_.empty)
this.to = (from_ == "J") ? "I" : "";
 
autoimmutable m = _canonicalize(key ~ uppercase)
.unique
.chunks(5)
.map!text
.array;
auto I5 = 5.iota;
 
foreach (constimmutable R; m)
foreach (immutable i, immutable j; cartesianProduct(I5, I5))
if (i != j)
Line 174 ⟶ 346:
 
foreach (immutable r; I5) {
constimmutable c = m.transversal(r).array;
foreach (immutable i, immutable j; cartesianProduct(I5, I5))
if (i != j)
Line 184 ⟶ 356:
enc[[m[i1][j1], m[i2][j2]]] = [m[i1][j2], m[i2][j1]];
 
dec = enc.byValuebyKeyValue.zipmap!(enct => tuple(t.value, t.byKeykey)).assocArray;
}
 
private string _canonicalize(in string s) const /*pure*/ @safe {
return s.toUpper.removechars("^A-Z").replace(from, to);
}
 
string encode(in string s) const /*pure @safe*/ {
return _canonicalize(s)
.matchAll(r"(.)(?:(?!\1)(.))?".regex)
//.map!(m => enc[m[0].leftJustify(2, 'X')])
.map!join(m => cast()enc[m[0].leftJustify(2,' 'X')]);
.join(" ");
}
 
string decode(in string s) const /*pure*/ @safe {
return _canonicalize(s).chunks(2).map!(p => dec[p.text]).join(' ');
.chunks(2)
//.map!dec
.map!(p => cast()dec[p.text])
.join(" ");
}
}
 
void main() /*@safe*/ {
/*immutable*/ const pf = Playfair("Playfair example");
immutable orig = "Hide the gold in...the TREESTUMP!!!";
writeln("Original: ", orig);
Line 215 ⟶ 382:
writeln(" Encoded: ", enc);
writeln(" Decoded: ", pf.decode(enc));
}</langsyntaxhighlight>
{{out}}
<pre>Original: Hide the gold in...the TREESTUMP!!!
Line 221 ⟶ 388:
Decoded: HI DE TH EG OL DI NT HE TR EX ES TU MP</pre>
 
=={{header|Perl 6FreeBASIC}}==
<syntaxhighlight lang="freebasic">' FB 1.05.0 Win64
<lang perl6># Instantiate a specific encoder/decoder.
 
Enum PlayFairOption
sub playfair( $key,
noQ
$from = 'J',
iEqualsJ
$to = $from eq 'J' ?? 'I' !! ''
End Enum
) {
 
Dim Shared pfo As PlayFairOption '' set this before calling buildTable
sub canon($str) { $str.subst(/<-alpha>/,'', :g).uc.subst(/$from/,$to,:g) }
Dim Shared table(1 To 5, 1 To 5) As UInteger
 
Sub buildTable(keyword As String)
# Build 5x5 matrix.
Dim used(1 To 26) As Boolean '' all false by default
my @m = canon($key ~ ('A'..'Z').join).comb.uniq.map:
If pfo = noQ Then
-> $a,$b,$c,$d,$e { [$a,$b,$c,$d,$e] }
used(17) = True
Else
used(10) = True
End If
Dim As String alphabet = UCase(keyword) + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
Dim As UInteger i = 1, j = 1, k
Dim As Integer c
For k = 0 To Len(alphabet) - 1
c = alphabet[k] - 64
If c < 1 OrElse c > 26 Then Continue For
If Not used(c) Then
table(i, j) = c
used(c) = True
j += 1
If j = 6 Then
i += 1
If i = 6 Then Return '' table has been filled
j = 1
End If
End If
Next k
End Sub
 
Function getCleanText(plainText As String) As String
# Pregenerate all forward translations.
plainText = UCase(plainText) '' ensure everything is upper case
my %ENC = gather {
' get rid of any non-letters and insert X between duplicate letters
# Map pairs in same row.
Dim As String cleanText = "", prevChar = "", nextChar
for @m -> @r {
For i As UInteger = 1 To Len(plainText)
for ^@r X ^@r -> \i,\j {
nextChar = Mid(plainText, i, 1)
next if i == j;
' It appears that Q should be omitted altogether if noQ option is specified - we assume so anyway
take @r[i] ~ @r[j] => @r[(i+1)%5] ~ @r[(j+1)%5];
If nextChar < "A" OrElse nextChar > "Z" OrElse (nextChar = "Q" AndAlso pfo = noQ) Then Continue For
}
' If iEqualsJ option specified, replace J with I
}
If nextChar = "J" AndAlso pfo = iEqualsJ Then nextChar = "I"
If nextChar <> prevChar Then
cleanText += nextChar
Else
cleanText += "X" + nextChar
End If
prevChar = nextChar
Next
If Len(cleanText) Mod 2 = 1 Then '' dangling letter at end so add another letter to complete digram
If Right(cleanText, 1) <> "X" Then
cleanText += "X"
Else
cleanText += "Z"
End If
End If
Return cleanText
End Function
Sub findChar(c As uInteger, ByRef row As UInteger, ByRef col As UInteger)
For i As UInteger = 1 To 5
For j As UInteger = 1 To 5
If table(i, j) = c Then
row = i
col = j
Return
End If
Next j
Next i
End Sub
Function encodePlayfair(plainText As String) As String
Dim As String cleanText = getCleanText(plainText)
Dim As String digram, cipherDigram, cipherText = ""
Dim As UInteger length = Len(cleanText)
Dim As UInteger char1, char2, row1, col1, row2, col2
For i As UInteger = 1 To length Step 2
digram = Mid(cleanText, i, 2)
char1 = digram[0] - 64
char2 = digram[1] - 64
findChar char1, row1, col1
findChar char2, row2, col2
If row1 = row2 Then
cipherDigram = Chr(table(row1, col1 Mod 5 + 1) + 64)
cipherDigram += Chr(table(row2, col2 Mod 5 + 1) + 64)
ElseIf col1 = col2 Then
cipherDigram = Chr(table(row1 Mod 5 + 1, col1) + 64)
cipherDigram += Chr(table(row2 Mod 5 + 1, col2) + 64)
Else
cipherDigram = Chr(table(row1, col2) + 64)
cipherDigram += Chr(table(row2, col1) + 64)
End If
cipherText += cipherDigram
If i < length Then cipherText += " "
Next i
Return cipherText
End Function
 
Function decodePlayfair(cipherText As String) As String
# Map pairs in same column.
Dim As String digram, cipherDigram, decodedText = ""
for ^5 -> $c {
Dim As UInteger length = Len(cipherText)
my @c = @m.map: *.[$c];
Dim As UInteger char1, char2, row1, col1, row2, col2
for ^@c X ^@c -> \i,\j {
For i As UInteger = 1 To length Step 3 '' cipherText will include spaces so we need to skip them
next if i == j;
cipherDigram = Mid(cipherText, i, 2)
take @c[i] ~ @c[j] => @c[(i+1)%5] ~ @c[(j+1)%5];
char1 = cipherDigram[0] - 64
}
char2 = cipherDigram[1] - 64
}
findChar char1, row1, col1
findChar char2, row2, col2
If row1 = row2 Then
digram = Chr(table(row1, IIf(col1 > 1, col1 - 1, 5)) + 64)
digram += Chr(table(row2, IIf(col2 > 1, col2 - 1, 5)) + 64)
ElseIf col1 = col2 Then
digram = Chr(table(IIf(row1 > 1, row1 - 1, 5), col1) + 64)
digram += Chr(table(IIf(row2 > 1, row2 - 1, 5), col2) + 64)
Else
digram = Chr(table(row1, col2) + 64)
digram += Chr(table(row2, col1) + 64)
End If
decodedText += digram
If i < length Then decodedText += " "
Next i
Return decodedText
End Function
 
Dim As String keyword, ignoreQ, plainText, encodedText, decodedText
# Map pairs with cross-connections.
Line Input "Enter Playfair keyword : "; keyword
for ^5 X ^5 X ^5 X ^5 -> \i1,\j1,\i2,\j2 {
 
next if i1 == i2 or j1 == j2;
Do
take @m[i1][j1] ~ @m[i2][j2] => @m[i1][j2] ~ @m[i2][j1];
Line Input "Ignore Q when buiding table y/n : "; ignoreQ
}
ignoreQ = LCase(ignoreQ)
Loop Until ignoreQ = "y" Or ignoreQ = "n"
 
pfo = IIf(ignoreQ = "y", noQ, iEqualsJ)
buildTable(keyword)
Print "The table to be used is : " : Print
For i As UInteger = 1 To 5
For j As UInteger = 1 To 5
Print Chr(table(i, j) + 64); " ";
Next j
Print
Next i
 
Print
Line Input "Enter plain text : "; plainText
Print
encodedText = encodePlayfair(plainText)
Print "Encoded text is : "; encodedText
decodedText = decodePlayFair(encodedText)
Print "Decoded text is : "; decodedText
Print
Print "Press any key to quit"
Sleep</syntaxhighlight>
Sample input/output:
{{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|Go}}==
{{trans|Kotlin}}
<syntaxhighlight lang="go">package main
 
import (
"bufio"
"fmt"
"os"
"strings"
)
 
type playfairOption int
 
const (
noQ playfairOption = iota
iEqualsJ
)
 
type playfair struct {
keyword string
pfo playfairOption
table [5][5]byte
}
 
func (p *playfair) init() {
// Build table.
var used [26]bool // all elements false
if p.pfo == noQ {
used[16] = true // Q used
} else {
used[9] = true // J used
}
alphabet := strings.ToUpper(p.keyword) + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
for i, j, k := 0, 0, 0; k < len(alphabet); k++ {
c := alphabet[k]
if c < 'A' || c > 'Z' {
continue
}
d := int(c - 65)
if !used[d] {
p.table[i][j] = c
used[d] = true
j++
if j == 5 {
i++
if i == 5 {
break // table has been filled
}
j = 0
}
}
}
}
 
func (p *playfair) getCleanText(plainText string) string {
// Ensure everything is upper case.
plainText = strings.ToUpper(plainText)
// Get rid of any non-letters and insert X between duplicate letters.
var cleanText strings.Builder
// Safe to assume null byte won't be present in plainText.
prevByte := byte('\000')
for i := 0; i < len(plainText); i++ {
nextByte := plainText[i]
// It appears that Q should be omitted altogether if NO_Q option is specified;
// we assume so anyway.
if nextByte < 'A' || nextByte > 'Z' || (nextByte == 'Q' && p.pfo == noQ) {
continue
}
// If iEqualsJ option specified, replace J with I.
if nextByte == 'J' && p.pfo == iEqualsJ {
nextByte = 'I'
}
if nextByte != prevByte {
cleanText.WriteByte(nextByte)
} else {
cleanText.WriteByte('X')
cleanText.WriteByte(nextByte)
}
prevByte = nextByte
}
l := cleanText.Len()
if l%2 == 1 {
// Dangling letter at end so add another letter to complete digram.
if cleanText.String()[l-1] != 'X' {
cleanText.WriteByte('X')
} else {
cleanText.WriteByte('Z')
}
}
return cleanText.String()
}
 
func (p *playfair) findByte(c byte) (int, int) {
for i := 0; i < 5; i++ {
for j := 0; j < 5; j++ {
if p.table[i][j] == c {
return i, j
}
}
}
return -1, -1
}
 
func (p *playfair) encode(plainText string) string {
cleanText := p.getCleanText(plainText)
var cipherText strings.Builder
l := len(cleanText)
for i := 0; i < l; i += 2 {
row1, col1 := p.findByte(cleanText[i])
row2, col2 := p.findByte(cleanText[i+1])
switch {
case row1 == row2:
cipherText.WriteByte(p.table[row1][(col1+1)%5])
cipherText.WriteByte(p.table[row2][(col2+1)%5])
case col1 == col2:
cipherText.WriteByte(p.table[(row1+1)%5][col1])
cipherText.WriteByte(p.table[(row2+1)%5][col2])
default:
cipherText.WriteByte(p.table[row1][col2])
cipherText.WriteByte(p.table[row2][col1])
}
if i < l-1 {
cipherText.WriteByte(' ')
}
}
return cipherText.String()
}
 
func (p *playfair) decode(cipherText string) string {
var decodedText strings.Builder
l := len(cipherText)
// cipherText will include spaces so we need to skip them.
for i := 0; i < l; i += 3 {
row1, col1 := p.findByte(cipherText[i])
row2, col2 := p.findByte(cipherText[i+1])
switch {
case row1 == row2:
temp := 4
if col1 > 0 {
temp = col1 - 1
}
decodedText.WriteByte(p.table[row1][temp])
temp = 4
if col2 > 0 {
temp = col2 - 1
}
decodedText.WriteByte(p.table[row2][temp])
case col1 == col2:
temp := 4
if row1 > 0 {
temp = row1 - 1
}
decodedText.WriteByte(p.table[temp][col1])
temp = 4
if row2 > 0 {
temp = row2 - 1
}
decodedText.WriteByte(p.table[temp][col2])
default:
decodedText.WriteByte(p.table[row1][col2])
decodedText.WriteByte(p.table[row2][col1])
}
if i < l-1 {
decodedText.WriteByte(' ')
}
}
return decodedText.String()
}
 
func (p *playfair) printTable() {
fmt.Println("The table to be used is :\n")
for i := 0; i < 5; i++ {
for j := 0; j < 5; j++ {
fmt.Printf("%c ", p.table[i][j])
}
fmt.Println()
}
}
 
func main() {
scanner := bufio.NewScanner(os.Stdin)
fmt.Print("Enter Playfair keyword : ")
scanner.Scan()
keyword := scanner.Text()
var ignoreQ string
for ignoreQ != "y" && ignoreQ != "n" {
fmt.Print("Ignore Q when building table y/n : ")
scanner.Scan()
ignoreQ = strings.ToLower(scanner.Text())
}
pfo := noQ
if ignoreQ == "n" {
pfo = iEqualsJ
}
var table [5][5]byte
pf := &playfair{keyword, pfo, table}
pf.init()
pf.printTable()
fmt.Print("\nEnter plain text : ")
scanner.Scan()
plainText := scanner.Text()
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, "reading standard input:", err)
return
}
encodedText := pf.encode(plainText)
fmt.Println("\nEncoded text is :", encodedText)
decodedText := pf.decode(encodedText)
fmt.Println("Deccoded text is :", decodedText)
}</syntaxhighlight>
 
{{out}}
Sample run:
<pre>
Enter Playfair keyword : Playfair example
Ignore Q when building 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
Deccoded text is : HI DE TH EG OL DI NT HE TR EX ES TU MP
</pre>
 
=={{header|Haskell}}==
{{incorrect|Haskell|TREESTUMP -> TREXSTUMPX, should be TREXESTUMP}}
(My guess is that map (\[x, y] -> if x == y then [x, 'x'] else [x, y]).chunksOf 2 is simply discarding the y. [[User:Petelomax|Pete Lomax]] ([[User talk:Petelomax|talk]]) 05:54, 13 October 2018 (UTC))
<syntaxhighlight lang="haskell">
import Control.Monad (guard)
import Data.Array (Array, assocs, elems, listArray, (!))
import Data.Char (toUpper)
import Data.List (nub, (\\))
import Data.List.Split (chunksOf)
import Data.Maybe (listToMaybe)
import Data.String.Utils (replace)
 
type Square a = Array (Int, Int) a
 
-- | Turns a list into an n*m-array.
array2D ::
(Int, Int) -- ^ n * m
-> [e] -> Square e
array2D maxCoord = listArray ((1, 1), maxCoord)
 
-- | Generates a playfair table starting with the specified string.
--
-- >>> makeTable "hello"
-- "HELOABCDFGIKMNPQRSTUVWXYZ"
makeTable :: String -> String
makeTable k = nub key ++ (alpha \\ key)
where
alpha = ['A' .. 'Z'] \\ "J"
key = map toUpper =<< words k
 
-- | Turns a playfair table into a 5*5 alphabet square.
makeSquare :: [a] -> Square a
makeSquare = array2D (5, 5)
 
-- | Displays a playfair square, formatted as a square.
showSquare :: Square Char -> String
showSquare d = unlines $ chunksOf 5 (elems d)
 
-- | Given a value and an association list of x-coordinate * y-coordinate * value, returns the coordinates
getIndex' :: (Eq a) => a -> [((Int, Int), a)] -> Maybe (Int, Int)
getIndex' el = fmap fst . listToMaybe . filter ((== el) . snd)
 
encodePair, decodePair :: Eq a => Square a -> (a, a) -> Maybe (a, a)
encodePair = pairHelper (\x -> if x == 5 then 1 else x + 1)
decodePair = pairHelper (\x -> if x == 1 then 5 else x - 1)
 
pairHelper :: (Eq t)
=> (Int -> Int) -- ^ a function used for wrapping around the square
-> Square t -- ^ a playfair square
-> (t, t) -- ^ two characters
-> Maybe (t, t) -- ^ the two resulting/encoded characters
pairHelper adjust sqr (c1, c2) =
do let ps = assocs sqr
-- assigns an association list of (x-coord * y-coord) * value to ps
(x1, y1) <- getIndex' c1 ps
(x2, y2) <- getIndex' c2 ps
-- returns the coordinates of two values in the square
-- these will later be swapped
guard $ c1 /= c2
-- the characters (and coordinates) cannot be the same
let get x = sqr ! x
-- a small utility function for extracting a value from the square
Just $
-- wrap the coordinates around and find the encrypted characters
case () of
() | y1 == y2 ->
(get (adjust x1, y1), get (adjust x2, y2))
| x1 == x2 ->
(get (x1, adjust y1), get (x2, adjust y2))
| otherwise ->
(get (x1, y2), get (x2, y1))
 
-- | Turns two characters into a tuple.
parsePair :: String -> [(Char, Char)]
parsePair = fmap (\[x, y] -> (x, y)) . words . fmap toUpper
 
-- | Turns a tuple of two characters into a string.
unparsePair :: [(Char, Char)] -> String
unparsePair = unwords . fmap (\(x, y) -> [x, y])
 
codeHelper :: (Square Char -> (Char, Char) -> Maybe (Char, Char))
-> String -> String -> Maybe String
codeHelper subs key =
fmap unparsePair .
mapM (subs (makeSquare $ makeTable key)) .
parsePair
 
playfair, unplayfair :: String -> String -> Maybe String
playfair key = codeHelper encodePair key . formatEncode
unplayfair = codeHelper decodePair
 
formatEncode :: String -> String
formatEncode =
map toUpper .
unwords .
map (\[x, y] -> if x == y then [x, 'x'] else [x, y]) .
chunksOf 2 .
replace "j" "i" .
concatMap adjustLength .
words .
filter (\n -> n `elem` (['A'..'Z'] ++ ['a'..'z']))
where
adjustLength str
| odd (length str) = str ++ "x"
| otherwise = str
</syntaxhighlight>
 
<pre>
>>> playfair "playfair example" "hide the gold in the tree stump"
Just "BM OD ZB XD NA BE KU DM UI XM KZ ZR YI"
 
>>> unplayfair "playfair example" "BM OD ZB XD NA BE KU DM UI XM KZ ZR YI"
Just "HI DE TH EG OL DI NT HE TR EX ST UM PX"
</pre>
 
=={{header|J}}==
Rather than implement two versions of the rules, one for encrypt, one for decrypt, let's just make a lookup table (mapping character pairs to character pairs). To decrypt we can look up in the other direction.
 
'''Implementation:'''
<syntaxhighlight lang="j">choose=: verb define
sel=. 'Q' e. y
alph=: (sel { 'JQ') -.~ a. {~ 65 + i.26
norm=: [: dedouble alph restrict ('I' I.@:=&'J'@]} ])`(-.&'Q')@.sel@toupper
''
)
 
restrict=: ] -. -.~
 
splitDigraph=: ,`([,'X',])@.((= {.) *. 2 | #@])
dedouble=: splitDigraph/&.|. NB. progressively split digraphs in string
 
choose 'Q'
setkey=: verb define
key=. ~.norm y,alph
ref=: ,/ 2{."1 ~."1 (,"0/~ alph) ,"1 norm 'XQV'
mode=. #. =/"2 inds=. 5 5#:key i. ref
inds0=. (0 3,:2 1)&{@,"2 inds
inds1=. 5|1 0 +"1 inds NB. same column
inds2=. 5|0 1 +"1 inds NB. same row
alt=: key {~ 5 #. mode {"_1 inds0 ,"2 3 inds1 ,:"2 inds2
i. 0 0
)
pairs=: verb define
2{."1 -.&' '"1 ~."1 (_2]\ norm y) ,"1 'XQV'
)
encrypt=: verb define
;:inv ;/ alt{~ref i. pairs y
)
decrypt=: verb define
, ref{~alt i. pairs y
)</syntaxhighlight>
 
'''Example use:'''
<syntaxhighlight lang="j"> choose 'IJ'
 
setkey 'playfair example'
encrypt 'Hide the gold in the tree stump'
BM OD ZB XD NA BE KU DM UI XM MO UV IF
decrypt 'BM OD ZB XD NA BE KU DM UI XM MO UV IF'
HIDETHEGOLDINTHETREXESTUMP</syntaxhighlight>
 
=={{header|Java}}==
<syntaxhighlight lang="java">import java.awt.Point;
import java.util.Scanner;
 
public class PlayfairCipher {
private static char[][] charTable;
private static Point[] positions;
 
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
 
String key = prompt("Enter an encryption key (min length 6): ", sc, 6);
String txt = prompt("Enter the message: ", sc, 1);
String jti = prompt("Replace J with I? y/n: ", sc, 1);
 
boolean changeJtoI = jti.equalsIgnoreCase("y");
 
createTable(key, changeJtoI);
 
String enc = encode(prepareText(txt, changeJtoI));
 
System.out.printf("%nEncoded message: %n%s%n", enc);
System.out.printf("%nDecoded message: %n%s%n", decode(enc));
}
 
private static String prompt(String promptText, Scanner sc, int minLen) {
String s;
do {
System.out.print(promptText);
s = sc.nextLine().trim();
} while (s.length() < minLen);
return s;
}
 
private static String prepareText(String s, boolean changeJtoI) {
s = s.toUpperCase().replaceAll("[^A-Z]", "");
return changeJtoI ? s.replace("J", "I") : s.replace("Q", "");
}
 
private static void createTable(String key, boolean changeJtoI) {
charTable = new char[5][5];
positions = new Point[26];
 
String s = prepareText(key + "ABCDEFGHIJKLMNOPQRSTUVWXYZ", changeJtoI);
 
int len = s.length();
for (int i = 0, k = 0; i < len; i++) {
char c = s.charAt(i);
if (positions[c - 'A'] == null) {
charTable[k / 5][k % 5] = c;
positions[c - 'A'] = new Point(k % 5, k / 5);
k++;
}
}
}
 
private static String encode(String s) {
StringBuilder sb = new StringBuilder(s);
 
for (int i = 0; i < sb.length(); i += 2) {
 
if (i == sb.length() - 1)
sb.append(sb.length() % 2 == 1 ? 'X' : "");
 
else if (sb.charAt(i) == sb.charAt(i + 1))
sb.insert(i + 1, 'X');
}
return codec(sb, 1);
}
 
private static String decode(String s) {
return codec(new StringBuilder(s), 4);
}
 
private static String codec(StringBuilder text, int direction) {
int len = text.length();
for (int i = 0; i < len; i += 2) {
char a = text.charAt(i);
char b = text.charAt(i + 1);
 
int row1 = positions[a - 'A'].y;
int row2 = positions[b - 'A'].y;
int col1 = positions[a - 'A'].x;
int col2 = positions[b - 'A'].x;
 
if (row1 == row2) {
col1 = (col1 + direction) % 5;
col2 = (col2 + direction) % 5;
 
} else if (col1 == col2) {
row1 = (row1 + direction) % 5;
row2 = (row2 + direction) % 5;
 
} else {
int tmp = col1;
col1 = col2;
col2 = tmp;
}
 
text.setCharAt(i, charTable[row1][col1]);
text.setCharAt(i + 1, charTable[row2][col2]);
}
return text.toString();
}
}</syntaxhighlight>
 
=== alternative version ===
 
<syntaxhighlight lang="java">import java.util.Scanner;
public class PlayfairCipherEncryption
{
private String KeyWord = new String();
private String Key = new String();
private char matrix_arr[][] = new char[5][5];
public void setKey(String k)
{
String K_adjust = new String();
boolean flag = false;
K_adjust = K_adjust + k.charAt(0);
for (int i = 1; i < k.length(); i++)
{
for (int j = 0; j < K_adjust.length(); j++)
{
if (k.charAt(i) == K_adjust.charAt(j))
{
flag = true;
}
}
if (flag == false)
K_adjust = K_adjust + k.charAt(i);
flag = false;
}
KeyWord = K_adjust;
}
public void KeyGen()
{
boolean flag = true;
char current;
Key = KeyWord;
for (int i = 0; i < 26; i++)
{
current = (char) (i + 97);
if (current == 'j')
continue;
for (int j = 0; j < KeyWord.length(); j++)
{
if (current == KeyWord.charAt(j))
{
flag = false;
break;
}
}
if (flag)
Key = Key + current;
flag = true;
}
System.out.println(Key);
matrix();
}
private void matrix()
{
int counter = 0;
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 5; j++)
{
matrix_arr[i][j] = Key.charAt(counter);
System.out.print(matrix_arr[i][j] + " ");
counter++;
}
System.out.println();
}
}
private String format(String old_text)
{
int i = 0;
int len = 0;
String text = new String();
len = old_text.length();
for (int tmp = 0; tmp < len; tmp++)
{
if (old_text.charAt(tmp) == 'j')
{
text = text + 'i';
}
else
text = text + old_text.charAt(tmp);
}
len = text.length();
for (i = 0; i < len; i = i + 2)
{
if (text.charAt(i + 1) == text.charAt(i))
{
text = text.substring(0, i + 1) + 'x' + text.substring(i + 1);
}
}
return text;
}
private String[] Divid2Pairs(String new_string)
{
String Original = format(new_string);
int size = Original.length();
if (size % 2 != 0)
{
size++;
Original = Original + 'x';
}
String x[] = new String[size / 2];
int counter = 0;
for (int i = 0; i < size / 2; i++)
{
x[i] = Original.substring(counter, counter + 2);
counter = counter + 2;
}
return x;
}
public int[] GetDiminsions(char letter)
{
int[] key = new int[2];
if (letter == 'j')
letter = 'i';
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 5; j++)
{
if (matrix_arr[i][j] == letter)
{
key[0] = i;
key[1] = j;
break;
}
}
}
return key;
}
public String encryptMessage(String Source)
{
String src_arr[] = Divid2Pairs(Source);
String Code = new String();
char one;
char two;
int part1[] = new int[2];
int part2[] = new int[2];
for (int i = 0; i < src_arr.length; i++)
{
one = src_arr[i].charAt(0);
two = src_arr[i].charAt(1);
part1 = GetDiminsions(one);
part2 = GetDiminsions(two);
if (part1[0] == part2[0])
{
if (part1[1] < 4)
part1[1]++;
else
part1[1] = 0;
if (part2[1] < 4)
part2[1]++;
else
part2[1] = 0;
}
else if (part1[1] == part2[1])
{
if (part1[0] < 4)
part1[0]++;
else
part1[0] = 0;
if (part2[0] < 4)
part2[0]++;
else
part2[0] = 0;
}
else
{
int temp = part1[1];
part1[1] = part2[1];
part2[1] = temp;
}
Code = Code + matrix_arr[part1[0]][part1[1]]
+ matrix_arr[part2[0]][part2[1]];
}
return Code;
}
public static void main(String[] args)
{
PlayfairCipherEncryption x = new PlayfairCipherEncryption();
Scanner sc = new Scanner(System.in);
System.out.println("Enter a keyword:");
String keyword = sc.next();
x.setKey(keyword);
x.KeyGen();
System.out
.println("Enter word to encrypt: (Make sure length of message is even)");
String key_input = sc.next();
if (key_input.length() % 2 == 0)
{
System.out.println("Encryption: " + x.encryptMessage(key_input));
}
else
{
System.out.println("Message length should be even");
}
sc.close();
}
}</syntaxhighlight>
 
=={{header|Julia}}==
<syntaxhighlight lang="julia">function playfair(key, txt, isencode=true, from = "J", to = "")
to = (to == "" && from == "J") ? "I" : to
 
function canonical(s, dup_toX=true)
s = replace(replace(uppercase(s), from => to), r"[^A-Z]" => "")
a, dupcount = [c for c in s], 0
for i in 1:2:length(a)-1
if s[i] == s[i + 1]
dup_toX && splice!(a, i+1+dupcount:i+dupcount, 'X')
dupcount += 1
end
end
s = String(a)
return isodd(length(s)) ? s * "X" : s
end
 
# Translate key into an encoding 5x5 translation matrix.
keyletters = unique([c for c in canonical(key * "ABCDEFGHIJKLMNOPQRSTUVWXYZ", false)])
m = Char.((reshape(UInt8.(keyletters[1:25]), 5, 5)'))
 
# encod is a dictionary of letter pairs for encoding.
encod = Dict()
 
# Map pairs in same row or same column of matrix m.
for i in 1:5, j in 1:5, k in 1:5
if j != k
encod[m[i, j] * m[i, k]] = m[i, mod1(j + 1, 5)] * m[i, mod1(k + 1, 5)]
end
if i != k
encod[m[i, j] * m[k, j]] = m[mod1(i + 1, 5), j] * m[mod1(k + 1, 5), j]
end
# Map pairs not on same row or same column.
for l in 1:5
if i != k && j != l
encod[m[i, j] * m[k, l]] = m[i, l] * m[k, j]
end
end
end
 
# Get array of pairs of letters from text.
canontxt = canonical(txt)
letterpairs = [canontxt[i:i+1] for i in 1:2:length(canontxt)-1]
 
if isencode
# Encode text
return join([encod[pair] for pair in letterpairs], " ")
else
# Decode text
decod = Dict((v, k) for (k, v) in encod)
return join([decod[pair] for pair in letterpairs], " ")
end
end
 
orig = "Hide the gold in...the TREESTUMP!!!"
println("Original: ", orig)
 
encoded = playfair("Playfair example", orig)
println("Encoded: ", encoded)
 
println("Decoded: ", playfair("Playfair example", encoded, false))
</syntaxhighlight>{{out}}
<pre>
Original: Hide the gold in...the TREESTUMP!!!
Encoded: BM OD ZB XD NA BE KU DM UI XM MO UV IF
Decoded: HI DE TH EG OL DI NT HE TR EX ES TU MP
</pre>
 
=={{header|Kotlin}}==
{{trans|FreeBASIC}}
<syntaxhighlight lang="scala">// version 1.0.5-2
 
enum class PlayfairOption {
NO_Q,
I_EQUALS_J
}
 
class Playfair(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)
}
 
fun encode(plainText: String): String {
val cleanText = getCleanText(plainText)
var cipherText = ""
val 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
}
 
fun decode(cipherText: String): String {
var decodedText = ""
val 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
}
 
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")
}</syntaxhighlight>
 
{{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|Mathematica}}/{{header|Wolfram Language}}==
<syntaxhighlight lang="mathematica">ClearAll[MakeTranslationTable, PlayfairCipher, PlayfairDecipher]
MakeTranslationTable[tt_List] := Module[{poss, in, out},
poss = Tuples[Tuples[Range[5], 2], 2];
Table[
If[p[[1, 1]] == p[[2, 1]],
(* same row *)
{in, out} = {p, {{p[[1, 1]], Mod[p[[1, 2]] + 1, 5, 1]}, {p[[2, 1]], Mod[p[[2, 2]] + 1, 5, 1]}}};
,
If[p[[1, 2]] == p[[2, 2]],
(* same column *)
{in, out} = {p, {{Mod[p[[1, 1]] + 1, 5, 1], p[[1, 2]]}, {Mod[p[[2, 1]] + 1, 5, 1], p[[2, 2]]}}};
,
(*rectangle*)
{in, out} = {p, {{p[[1, 1]], p[[2, 2]]}, {p[[2, 1]], p[[1, 2]]}}};
]
];
StringJoin[Extract[tt, in]] -> StringJoin[Extract[tt, out]]
,
{p, poss}
]
]
PlayfairCipher[txt_String, key_String, iisj_ : True] :=
Module[{text, tt},
text = RemoveDiacritics[ToUpperCase[txt]];
tt = RemoveDiacritics[ToUpperCase[key]] <> CharacterRange["A", "Z"];
text //= StringReplace[Except[Alternatives @@ CharacterRange["A", "Z"]] -> ""];
tt //= StringReplace[Except[Alternatives @@ CharacterRange["A", "Z"]] -> ""];
If[iisj,
tt //= StringReplace["J" -> "I"];
text //= StringReplace["J" -> "I"];
,
tt //= StringReplace["Q" -> ""];
text //= StringReplace["Q" -> ""];
];
tt //= Characters /* DeleteDuplicates;
text = FixedPoint[StringReplace[#, x_ ~~ x_ :> x ~~ "X" ~~ x, 1] &, text];
If[OddQ[StringLength[text]], text = text <> "X"];
If[Length[tt] == 25,
tt = Partition[tt, 5];
tt = MakeTranslationTable[tt];
text = StringPartition[text, 2];
StringRiffle[text /. tt, " "]
,
Print["Something went wrong!"]
]
]
PlayfairDecipher[txt_String, key_String, iisj_ : True] :=
Module[{text, tt},
text = RemoveDiacritics[ToUpperCase[txt]];
tt = RemoveDiacritics[ToUpperCase[key]] <> CharacterRange["A", "Z"];
text //= StringReplace[Except[Alternatives @@ CharacterRange["A", "Z"]] -> ""];
tt //= StringReplace[Except[Alternatives @@ CharacterRange["A", "Z"]] -> ""];
If[iisj,
tt //= StringReplace["J" -> "I"];
text //= StringReplace["J" -> "I"];
,
tt //= StringReplace["Q" -> ""];
text //= StringReplace["Q" -> ""];
];
tt //= Characters /* DeleteDuplicates;
If[OddQ[StringLength[text]], text = text <> "X"];
If[Length[tt] == 25,
tt = Partition[tt, 5];
tt = MakeTranslationTable[tt];
text = StringPartition[text, 2];
StringRiffle[text /. (Reverse /@ tt), " "]
,
Print["Something went wrong!"]
]
]
PlayfairCipher["Hide the gold in...the TREESTUMP!!!", "Playfair example"]
PlayfairDecipher[%, "Playfair example"]</syntaxhighlight>
{{out}}
<pre>BM OD ZB XD NA BE KU DM UI XM MO UV IF
HI DE TH EG OL DI NT HE TR EX ES TU MP</pre>
 
=={{header|Nim}}==
{{trans|Java}}
<syntaxhighlight lang="nim">import pegs, strutils
 
type
Position = tuple[x, y: int]
Playfair = object
positions: array['A'..'Z', Position]
table: array[5, array[5, char]]
 
const None: Position = (-1, -1) # Default value for positions.
 
 
proc initPlayfair(key: string; jti: bool): Playfair =
 
for item in result.positions.mitems: item = None
 
var alphabet = key & "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
alphabet = if jti: alphabet.replace('J', 'I')
else: alphabet.replace("Q", "")
 
var k = 0
for ch in alphabet:
if result.positions[ch] == None:
result.table[k div 5][k mod 5] = ch
result.positions[ch] = (k mod 5, k div 5)
inc k
 
 
proc codec(playfair: Playfair; text: string; direction: int): string =
 
result.setLen(text.len)
 
for i in countup(0, text.high, 2):
var
(col1, row1) = playfair.positions[text[i]]
(col2, row2) = playfair.positions[text[i + 1]]
 
if row1 == row2:
col1 = (col1 + direction) mod 5
col2 = (col2 + direction) mod 5
elif col1 == col2:
row1 = (row1 + direction) mod 5
row2 = (row2 + direction) mod 5
else:
swap col1, col2
 
result[i] = playfair.table[row1][col1]
result[i + 1] = playfair.table[row2][col2]
 
 
proc encode(playfair: Playfair; text: string): string =
var
text = text
i = 0
 
while i < text.len:
if i == text.high:
if (text.len and 1) != 0:
text.add 'X'
elif text[i] == text[i + 1]:
text.insert("X", i + 1)
inc i, 2
 
result = playfair.codec(text, 1)
 
 
proc decode(playfair: Playfair; text: string): string =
result = playfair.codec(text, 4)
 
 
proc prompt(msg: string): string =
stdout.write msg
try:
result = stdin.readLine()
except EOFError:
echo ""
quit getCurrentExceptionMsg(), QuitFailure
 
 
when isMainModule:
 
var key: string
while key.len <= 6:
key = prompt("Enter an encryption key (min letters 6): ").toUpperAscii().replace(peg"[^A-Z]")
 
var text: string
while text.len == 0:
text = prompt("Enter the message: ").toUpperAscii().replace(peg"[^A-Z]")
 
var answer: string
while answer notin ["y", "n"]:
answer = prompt("Replace J with I? y/n: ").toLowerAscii()
let jti = (answer == "y")
 
let playfair = initPlayfair(key, jti)
let enc = playfair.encode(text)
let dec = playfair.decode(enc)
 
echo "Encoded message: ", enc
echo "Decoded message: ", dec</syntaxhighlight>
 
{{out}}
<pre>Enter an encryption key (min letters 6): Playfair example
Enter the message: Hide the gold...in the TREESTUMP!!!
Replace J with I? y/n: y
Encoded message: BMODZBXDNABEKUDMUIXMMOUVIF
Decoded message: HIDETHEGOLDINTHETREXESTUMP</pre>
 
=={{header|NetRexx}}==
<syntaxhighlight lang="netrexx">/* NetRexx */
options replace format comments java crossref symbols nobinary
 
-- input arguments:
-- encipher/decipher IQ-switch key text
-- encipher/decipher -
-- a character E, D (default E; . is an alias for E)
-- IQ-switch -
-- a character I, Q (default I for I==J, Q for exclude Q; . is an alias for I)
-- key -
-- the cipher key - default plugh_xyzzy (really just PLUGHXYZ)
-- text -
-- the text to encipher/decipher
 
runSample(arg)
return
 
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
method cipher(d_, km, digraphs) public static
if d_.upper() = 'D' then d_ = -1 -- encode or decode adjustment
else d_ = +1
cipherText = ''
loop dw = 1 to digraphs.words()
-- process the digraphs one at a time
digraph = digraphs.word(dw)
cl = ''
cr = ''
-- get each letter from the digraph
parse digraph dl +1 dr
loop r_ = 1 to km[0] while (cl cr).words() < 4
-- locate the row/col of each letter in the cipher matrix
clx = km[r_].wordpos(dl)
crx = km[r_].wordpos(dr)
if clx > 0 then cl = r_ clx
if crx > 0 then cr = r_ crx
end r_
 
-- process the digraph's rows, columns or rectangles
select
when cl.word(1) = cr.word(1) then do
-- a row
rx = cl.word(1)
clx = cl.word(2) + d_
crx = cr.word(2) + d_
if clx > 5 then clx = 1 -- wrap
if crx > 5 then crx = 1
if clx < 1 then clx = 5
if crx < 1 then crx = 5
cy = km[rx].word(clx) || km[rx].word(crx)
cipherText = cipherText cy
end
when cl.word(2) = cr.word(2) then do
-- a column
cx = cl.word(2)
rlx = cl.word(1) + d_
rrx = cr.word(1) + d_
if rlx > 5 then rlx = 1 -- wrap
if rrx > 5 then rrx = 1
if rlx < 1 then rlx = 5
if rrx < 1 then rrx = 5
cy = km[rlx].word(cx) || km[rrx].word(cx)
cipherText = cipherText cy
end
otherwise do
-- a rectangle
r1 = cl.word(1)
r2 = cr.word(1)
cy = km[r1].word(cr.word(2)) || km[r2].word(cl.word(2))
cipherText = cipherText cy
end
end
end dw
return cipherText.strip()
 
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
method encipher(km, digraphs) public static
return cipher('E', km, digraphs)
 
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
method decipher(km, digraphs) public static
return cipher('D', km, digraphs)
 
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
method getDigraphs(text, IorQ, ED) private static
a2z = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
if ED.upper() \= 'D' then eks = 'X'
else eks = ''
tp = text.upper().translate('', a2z)
text = text.upper().translate(' '.copies(tp.length()), tp).space(0)
rtext = ''
ll = ''
 
loop while text \= ''
parse text lc +1 text
if ll \= lc then rtext = rtext || lc
else rtext = rtext || eks || lc
ll = lc
end
 
-- I == J or remove Q fixup
if IorQ \= 'Q' then
parse 'J I' IorQ sc .
else
sc = ''
 
rtext = rtext.changestr(IorQ, sc)
if rtext.length() // 2 \= 0 then rtext = rtext || eks
digraphs = ''
loop while rtext \= ''
parse rtext digraph +2 rtext
digraphs = digraphs digraph
end
return digraphs.space()
 
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
method getKey(key, IorQ) private static
a2z = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
kp = (key || a2z).upper()
kr = ''
loop while kp \= ''
parse kp xx +1 kp
if \xx.datatype('u') then iterate
kr = kr xx
kp = kp.changestr(xx, '')
end
 
if IorQ = 'I' | IorQ = 'J' | IorQ = '' then
kr = kr.changestr('J', '')
else
kr = kr.changestr('Q', '')
 
return kr.space()
 
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
method getKeyMatrix(kr) private static
km = ''
loop r_ = 1 while kr \= ''
parse kr kp +10 kr
km[0] = r_
km[r_] = kp
end r_
return km
 
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
method runSample(arg) private static
parse arg ciph IorQ key text
if ciph = '' | ciph = '.' then ciph = 'E'
if IorQ = '' | IorQ = '.' then IorQ = 'I'
if key = '' | key = '.' then key = 'plugh_xyzzy'
if text = '' | text = '.' then text = 'NetRexx; not just a programing language for kings & queens!'
 
kr = getKey(key.space(0), IorQ)
km = getKeyMatrix(kr)
 
digraphs = getDigraphs(text, IorQ, ciph)
-- fixup for a Q in the text when Q is excluded (substitute K for Q)
if IorQ.upper = 'Q' then digraphs = digraphs.changestr('Q', 'K')
if ciph = 'E' then say text
say digraphs
if ciph.upper() = 'E' then
say encipher(km, digraphs)
else
say decipher(km, digraphs)
 
return
</syntaxhighlight>
{{out}}
<pre>
$ java -cp .:.. RPlayfairCipher00
NetRexx; not just a programing language for kings & queens!
NE TR EX XX NO TI US TA PR OG RA MI NG LA NG UA GE FO RK IN GS QU EX EN SX
TN VS CZ YY OQ WE LT VZ XP VA VX QD OU GY OU GZ UF OV PR EQ LV NH CZ NT RY
 
$ java -cp .:.. RPlayfairCipher00 d . . TN VS CZ YY OQ WE LT VZ XP VA VX QD OU GY OU GZ UF OV PR EQ LV NH CZ NT RY
TN VS CZ YY OQ WE LT VZ XP VA VX QD OU GY OU GZ UF OV PR EQ LV NH CZ NT RY
NE TR EX XX NO TI US TA PR OG RA MI NG LA NG UA GE FO RK IN GS QU EX EN SX
 
$ java -cp .:.. RPlayfairCipher00 e q playfair Hide the gold in the tree stump\!\!
Hide the gold in the tree stump!!
HI DE TH EG OL DI NT HE TR EX ES TU MP
EB IK OK GH NA IR OM JG ND JU JM MZ UI
 
$ java -cp .:.. RPlayfairCipher00 d q playfair EB IK OK GH NA IR OM JG ND JU JM MZ UI
EB IK OK GH NA IR OM JG ND JU JM MZ UI
HI DE TH EG OL DI NT HE TR EX ES TU MP
</pre>
 
=={{header|ooRexx}}==
<syntaxhighlight lang="oorexx">/*---------------------------------------------------------------------
* REXX program implements a PLAYFAIR cipher (encryption & decryption).
* 11.11.2013 Walter Pachl revamped, for ooRexx, the REXX program
* the logic of which was devised by Gerard Schildberger
* Invoke as rexx pf O abcd efgh ( phrase to be processed
* Defaults: 'Playfair example.'
* J
* 'Hide the gold in the tree stump'
* Major changes: avoid language elements not allowed in ooRexx
* show use of a.[expr1,expr2]
* allow key to be more than one word
* add restriction of using X or Q in text
* 12.11.2013 change order of arguments
* and comment the use of a.[expr1,expr2]
* Program should run on all Rexxes that have changestr-bif
*--------------------------------------------------------------------*/
Parse Upper Version v
oorexx=pos('OOREXX',v)>0
 
Parse Arg omit oldk '(' text
If omit='' Then omit='J'
If oldk='' Then oldk='Playfair example.'
If text='' Then text='Hide the gold in the tree stump!!'
 
newkey=scrub(oldk,1)
newtext=scrub(text)
If newtext=='' Then Call err 'TEXT is empty or has no letters'
If length(omit)\==1 Then Call err 'OMIT letter must be only one letter'
If\datatype(omit,'M') Then Call err 'OMIT letter must be a Latin alphabet letter.'
omit=translate(omit)
cant='must not contain the "OMIT" character: ' omit
If pos(omit,newtext)\==0 Then Call err 'TEXT' cant
If pos(omit,newkey)\==0 Then Call err 'cipher key' cant
abc='abcdefghijklmnopqrstuvwxyz'
abcu=translate(abc) /* uppercase alphabet */
abcx=space(translate(abcu,,omit),0) /*elide OMIT char from alphabet */
xx='X' /* char used for double characters*/
If omit==xx Then
xx='Q'
If pos(xx,newtext)>0 Then
Call err 'Sorry,' xx 'is not allowed in text'
If length(newkey)<3 Then
Call err 'cipher key is too short, must be at least 3 different letters'
abcx=space(translate(abcx,,newkey),0) /*remove any cipher characters */
grid=newkey||abcx /* only first 25 chars are used*/
Say 'old cipher key: ' strip(oldk)
padl=14+2
pad=left('',padl)
Say 'new cipher key: ' newkey
padx=left('',padl,"-")'Playfair'
Say ' omit char: ' omit /* [?] lowercase of double char. */
Say ' double char: ' xx
lxx=translate(xx,abc,abcu)
Say ' original text: ' strip(text)/* [?] doubled version of Lxx. */
Call show 'cleansed',newtext
lxxlxx=lxx||lxx
n=0 /* number of grid characters used.*/
Do row=1 For 5 /* build array of individual cells*/
Do col=1 For 5
n=n+1
a.row.col=substr(grid,n,1)
If row==1 Then
a.0.col=a.1.col
If col==5 Then Do
a.row.6=a.row.1
a.row.0=a.row.5
End
If row==5 Then Do
a.6.col=a.1.col
a.0.col=a.5.col
End
End
End
 
etext=playfair(newtext,1)
Call show 'encrypted',etext
ptext=playfair(etext,-1)
Call show 'plain',ptext
qtext=changestr(xx||xx,ptext,lxx) /*change doubled doublechar-?sing*/
qtext=changestr(lxx||xx,qtext,lxxlxx) /*change Xx --? lowercase dblChar*/
qtext=space(translate(qtext,,xx),0) /*remove char used for "doubles."*/
qtext=translate(qtext) /*reinstate the use of upperchars*/
Call show 'decoded',qtext
Say ' original text: ' newtext /* ·· and show the original text.*/
Say ''
Exit
 
playfair:
/*---------------------------------------------------------------------
* encode (e=1) or decode (e=-1) the given text (t) using the grid
*--------------------------------------------------------------------*/
Arg t,e
d=''
If e=1 Then Do
Do k=1 By 1 Until c=''
c=substr(t,k,1)
If substr(t,k+1,1)==c Then
t=left(t,k)||lxx||substr(t,k+1)
End
End
t=translate(t)
Do j=1 By 2 To length(t)
c2=strip(substr(t,j,2))
If length(c2)==1 Then
c2=c2||xx /* append X or Q char, rule 1*/
Call LR
Select
/*- This could/should be used on ooRexx -------------------------
When rowl==rowr Then c2=a.[rowl,coll+e]a.[rowr,colr+e] /*rule 2*/
When coll==colr Then c2=a.[rowl+e,coll]a.[rowr+e,colr] /*rule 3*/
*--------------------------------------------------------------*/
When rowl==rowr Then c2=aa(rowl,coll+e)aa(rowr,colr+e) /*rule 2*/
When coll==colr Then c2=aa(rowl+e,coll)aa(rowr+e,colr) /*rule 3*/
Otherwise c2=a.rowl.colr||a.rowr.coll /*rule 4*/
End
d=d||c2
End
Return d
 
aa:
/*---------------------------------------------------------------------
* ooRexx allows to use a.[rowl,coll+e]
* this function can be removed when ooRexx syntax is used to access a.
*--------------------------------------------------------------------*/
Parse Arg xrow,xcol
Return a.xrow.xcol
 
err:
/*---------------------------------------------------------------------
* Exit with an error message
*--------------------------------------------------------------------*/
Say
Say '***error!***' arg(1)
Say
Exit 13
 
lr:
/*---------------------------------------------------------------------
* get grid positions of the 2 characters
*--------------------------------------------------------------------*/
Parse Value rowcol(left(c2,1)) with rowl coll
Parse Value rowcol(right(c2,1)) with rowr colr
Return
 
rowcol: procedure Expose grid
/*---------------------------------------------------------------------
* compute row and column of the given character in the 5x5 grid
*--------------------------------------------------------------------*/
Parse Arg c
p=pos(c,grid)
col=(p-1)//5+1
row=(4+p)%5
Return row col
 
show:
/*---------------------------------------------------------------------
* Show heading and text
*--------------------------------------------------------------------*/
Arg,y
Say
Say right(arg(1) 'text: ',padl) digram(arg(2))
result=space(arg(2),0)
If arg(1)='decoded' Then Do
result=strip(result,'T',xx)
End
Say pad result
Return
 
scrub: Procedure
/*---------------------------------------------------------------------
* Remove all non-letters from the given string, uppercase letters
* and, if unique=1 remove duplicates
* 'aB + c1Bb' -> 'ABCBB' or 'ABC', respectively
*--------------------------------------------------------------------*/
Arg xxx,unique /* ARG caps all args */
d=''
used.=0
Do While xxx<>''
Parse Var xxx c +1 xxx
If datatype(c,'U') Then
If (unique=1 & pos(c,d)=0) |,
unique<>1 Then
d=d||c
End
Return d
 
digram: Procedure
/*---------------------------------------------------------------------
* Return the given string as character pairs separated by blanks
* 'ABCDEF' -> 'AB CD EF'
* 'ABCDE' -> 'AB CD E'
*--------------------------------------------------------------------*/
Parse Arg x
d=''
Do j=1 By 2 To length(x)
d=d||substr(x,j,2)' '
End
Return strip(d)</syntaxhighlight>
Output (sample):
<pre>old cipher key: this is my little key
new cipher key: THISMYLEK
omit char: X
double char: Q
original text: to be or not to bee
 
cleansed text: TO BE OR NO TT OB EE
TOBEORNOTTOBEE
 
encrypted text: IJ DY JV OP MJ IJ DY OA JJ
IJDYJVOPMJIJDYOAJJ
 
plain text: TO BE OR NO TQ TO BE QE QQ
TOBEORNOTQTOBEQEQQ
 
decoded text: TO BE OR NO TT OB EE Q
TOBEORNOTTOBEE
original text: TOBEORNOTTOBEE</pre>
 
=={{header|Perl}}==
{{trans|Raku}}
<syntaxhighlight lang="perl">use Math::Cartesian::Product;
 
# Pregenerate all forward and reverse translations
sub playfair {
our($key,$from) = @_;
$from //= 'J';
our $to = $from eq 'J' ? 'I' : '';
my(%ENC,%DEC,%seen,@m);
 
sub canon {
my($str) = @_;
$str =~ s/[^[:alpha:]]//g;
$str =~ s/$from/$to/gi;
uc $str;
}
 
my @uniq = grep { ! $seen{$_}++ } split '', canon($key . join '', 'A'..'Z');
while (@uniq) { push @m, [splice @uniq, 0, 5] }
 
# Map pairs in same row.
for my $r (@m) {
for my $x (cartesian {@_} [0..4], [0..4]) {
my($i,$j) = @$x;
next if $i == $j;
$ENC{ @$r[$i] . @$r[$j] } = @$r[($i+1)%5] . @$r[($j+1)%5];
}
}
 
# Map pairs in same column.
for my $c (0..4) {
my @c = map { @$_[$c] } @m;
for my $x (cartesian {@_} [0..4], [0..4]) {
my($i,$j) = @$x;
next if $i == $j;
$ENC{ $c[$i] . $c[$j] } = $c[($i+1)%5] . $c[($j+1)%5];
}
}
 
# Map pairs with cross-connections.
for my $x (cartesian {@_} [0..4], [0..4], [0..4], [0..4]) {
my($i1,$j1,$i2,$j2) = @$x;
next if $i1 == $i2 or $j1 == $j2;
$ENC{ $m[$i1][$j1] . $m[$i2][$j2] } = $m[$i1][$j2] . $m[$i2][$j1];
}
 
# Generate reverse translations.
while (my %DEC($k, $v) = each %ENC.invert;) { $DEC{$v} = $k }
 
# Return code-refs for encoding/decoding routines
return
anon sub enc{ my($red) {= @_; # encode
my @list$str = canon($red).comb(/(.) (.?) <?{ $1 ne $0 }>/);
 
~@list.map: { .chars == 1 ?? %ENC{$_~'X'} !! %ENC{$_} }
my @list;
},
while ($str =~ /(.)(?(?=\1)|(.?))/g) {
anon sub dec($black) {
my push @list, = canonsubstr($black).comb(/../str,$-[0], $-[2] ? 2 : 1);
~@list.map: { %DEC{$_} }
join ' ', map { length($_)==1 ? $ENC{$_.'X'} : $ENC{$_} } @list;
}
},
sub { my($black) = @_; # decode
join ' ', map { $DEC{$_} } canon($black) =~ /../g;
}
}
 
my (&$encode,&$decode) = playfair ('Playfair example');
 
my $orig = "Hide the gold in...the TREESTUMP!!!";
saymy "$black orig:\t= &$encode($orig");
my $red = &$decode($black);
 
myprint $black = encode" orig:\t$orig\n";
sayprint "black:\t$black\n";
print " red:\t$red\n";</syntaxhighlight>
{{out}}
<pre> orig: Hide the gold in...the TREESTUMP!!!
black: BM OD ZB XD NA BE KU DM UI XM MO UV IF
red: HI DE TH EG OL DI NT HE TR EX ES TU MP
</pre>
 
=={{header|Phix}}==
my $red = decode $black;
Originally translated from Kotlin, now uses a combined routine (playfair) for encoding and decoding, and direct char lookups, and x removal.
say " red:\t$red";</lang>
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">keyword</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"Playfair example"</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">option</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">'Q'</span> <span style="color: #000080;font-style:italic;">-- ignore Q
-- option = 'J' -- replace J with I</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">table</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">findchar</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">build_table</span><span style="color: #0000FF;">()</span>
<span style="color: #000000;">table</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">' '</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5</span><span style="color: #0000FF;">),</span><span style="color: #000000;">5</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">findchar</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">26</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">findchar</span><span style="color: #0000FF;">[</span><span style="color: #000000;">option</span><span style="color: #0000FF;">-</span><span style="color: #008000;">'A'</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">}</span>
<span style="color: #000080;font-style:italic;">-- (note any (J/Q) in keyword are simply ignored)</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">alphabet</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">upper</span><span style="color: #0000FF;">(</span><span style="color: #000000;">keyword</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">&</span> <span style="color: #7060A8;">tagset</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'Z'</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'A'</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">k</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">c</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">alphabet</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">>=</span><span style="color: #008000;">'A'</span> <span style="color: #008080;">and</span> <span style="color: #000000;">c</span><span style="color: #0000FF;"><=</span><span style="color: #008000;">'Z'</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">d</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">-</span><span style="color: #008000;">'A'</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">findchar</span><span style="color: #0000FF;">[</span><span style="color: #000000;">d</span><span style="color: #0000FF;">]=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">table</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">j</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">c</span>
<span style="color: #000000;">findchar</span><span style="color: #0000FF;">[</span><span style="color: #000000;">d</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">i</span><span style="color: #0000FF;">,</span><span style="color: #000000;">j</span><span style="color: #0000FF;">}</span>
<span style="color: #000000;">j</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">=</span><span style="color: #000000;">6</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">i</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">6</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span> <span style="color: #000080;font-style:italic;">-- table filled</span>
<span style="color: #000000;">j</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #000000;">build_table</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">clean_text</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">plaintext</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">--
-- get rid of any non-letters and insert X between duplicate letters
--</span>
<span style="color: #000000;">plaintext</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">upper</span><span style="color: #0000FF;">(</span><span style="color: #000000;">plaintext</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">cleantext</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">prevChar</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">plaintext</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">nextChar</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">plaintext</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">nextChar</span><span style="color: #0000FF;">>=</span><span style="color: #008000;">'A'</span> <span style="color: #008080;">and</span> <span style="color: #000000;">nextChar</span><span style="color: #0000FF;"><=</span><span style="color: #008000;">'Z'</span>
<span style="color: #008080;">and</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">nextChar</span><span style="color: #0000FF;">!=</span><span style="color: #008000;">'Q'</span> <span style="color: #008080;">or</span> <span style="color: #000000;">option</span><span style="color: #0000FF;">!=</span><span style="color: #008000;">'Q'</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">nextChar</span><span style="color: #0000FF;">=</span><span style="color: #008000;">'J'</span> <span style="color: #008080;">and</span> <span style="color: #000000;">option</span><span style="color: #0000FF;">=</span><span style="color: #008000;">'J'</span> <span style="color: #008080;">then</span> <span style="color: #000000;">nextChar</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">'I'</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">nextChar</span><span style="color: #0000FF;">=</span><span style="color: #000000;">prevChar</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">cleantext</span> <span style="color: #0000FF;">&=</span> <span style="color: #008000;">'X'</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">cleantext</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">nextChar</span>
<span style="color: #000000;">prevChar</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">nextChar</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">odd</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cleantext</span><span style="color: #0000FF;">))</span> <span style="color: #008080;">then</span>
<span style="color: #000080;font-style:italic;">-- dangling letter at end so add another letter to complete digraph</span>
<span style="color: #000000;">cleantext</span> <span style="color: #0000FF;">&=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cleantext</span><span style="color: #0000FF;">[$]=</span><span style="color: #008000;">'X'</span><span style="color: #0000FF;">?</span><span style="color: #008000;">'Z'</span><span style="color: #0000FF;">:</span><span style="color: #008000;">'X'</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">cleantext</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">remove_x</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">text</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">2</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">text</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">text</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]=</span><span style="color: #008000;">'X'</span>
<span style="color: #008080;">and</span> <span style="color: #0000FF;">((</span><span style="color: #000000;">text</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]=</span><span style="color: #008000;">' '</span> <span style="color: #008080;">and</span> <span style="color: #000000;">text</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">-</span><span style="color: #000000;">2</span><span style="color: #0000FF;">]=</span><span style="color: #000000;">text</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">])</span> <span style="color: #008080;">or</span>
<span style="color: #0000FF;">(</span><span style="color: #000000;">text</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]=</span><span style="color: #008000;">' '</span> <span style="color: #008080;">and</span> <span style="color: #000000;">text</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]=</span><span style="color: #000000;">text</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">+</span><span style="color: #000000;">2</span><span style="color: #0000FF;">]))</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">text</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">'_'</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">text</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">playfair</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">text</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">step</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">sequence</span> <span style="color: #000000;">d</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">--
-- text may be the plaintext or the encoded version
-- step is 2 for plaintext, 3 for encoded(/skip spaces)
-- d is {2,3,4,5,1} instead of mod(+1,5), or
-- {5,1,2,3,4} -- -1
--</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">text</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">by</span> <span style="color: #000000;">step</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">row1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">col1</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">findchar</span><span style="color: #0000FF;">[</span><span style="color: #000000;">text</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]-</span><span style="color: #008000;">'A'</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">],</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">row2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">col2</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">findchar</span><span style="color: #0000FF;">[</span><span style="color: #000000;">text</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]-</span><span style="color: #008000;">'A'</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">></span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">&=</span> <span style="color: #008000;">" "</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">row1</span><span style="color: #0000FF;">=</span><span style="color: #000000;">row2</span> <span style="color: #008080;">then</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">col1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">col2</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">d</span><span style="color: #0000FF;">[</span><span style="color: #000000;">col1</span><span style="color: #0000FF;">],</span><span style="color: #000000;">d</span><span style="color: #0000FF;">[</span><span style="color: #000000;">col2</span><span style="color: #0000FF;">]}</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">col1</span><span style="color: #0000FF;">=</span><span style="color: #000000;">col2</span> <span style="color: #008080;">then</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">row1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">row2</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">d</span><span style="color: #0000FF;">[</span><span style="color: #000000;">row1</span><span style="color: #0000FF;">],</span><span style="color: #000000;">d</span><span style="color: #0000FF;">[</span><span style="color: #000000;">row2</span><span style="color: #0000FF;">]}</span>
<span style="color: #008080;">else</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">col1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">col2</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">col2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">col1</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">table</span><span style="color: #0000FF;">[</span><span style="color: #000000;">row1</span><span style="color: #0000FF;">][</span><span style="color: #000000;">col1</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">table</span><span style="color: #0000FF;">[</span><span style="color: #000000;">row2</span><span style="color: #0000FF;">][</span><span style="color: #000000;">col2</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">res</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">encode</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">plaintext</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">playfair</span><span style="color: #0000FF;">(</span><span style="color: #000000;">clean_text</span><span style="color: #0000FF;">(</span><span style="color: #000000;">plaintext</span><span style="color: #0000FF;">),</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">decode</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">ciphertext</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- ciphertext includes spaces we need to skip, hence by 3</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">remove_x</span><span style="color: #0000FF;">(</span><span style="color: #000000;">playfair</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ciphertext</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">}))</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Playfair keyword : %s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">keyword</span><span style="color: #0000FF;">})</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Option: J=I or no Q (J/Q) : %s\n"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">option</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"The table to be used is :\n\n%s\n\n"</span><span style="color: #0000FF;">,{</span><span style="color: #7060A8;">join</span><span style="color: #0000FF;">(</span><span style="color: #000000;">table</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\n"</span><span style="color: #0000FF;">)})</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">plaintext</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"Hide the gold...in the TREESTUMP!!!!"</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">encoded</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">encode</span><span style="color: #0000FF;">(</span><span style="color: #000000;">plaintext</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">decoded</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">decode</span><span style="color: #0000FF;">(</span><span style="color: #000000;">encoded</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"The plain text : %s\n\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">plaintext</span><span style="color: #0000FF;">})</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Encoded text is : %s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">encoded</span><span style="color: #0000FF;">})</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Decoded text is : %s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">decoded</span><span style="color: #0000FF;">})</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
<pre> orig: Hide the gold in...the TREESTUMP!!!
Playfair keyword : Playfair example
black: BM OD ZB XD NA BE KU DM UI XM MO UV IF
Option: J=I or no Q (J/Q) : Q
red: HI DE TH EG OL DI NT HE TR EX ES TU MP</pre>
The table to be used is :
 
PLAYF
IREXM
BCDGH
JKNOS
TUVWZ
 
The plain text : Hide the gold...in the TREESTUMP!!!!
 
Encoded text is : BM ND ZB XD KY BE JV DM UI XM MN UV IF
Decoded text is : HI DE TH EG OL DI NT HE TR E_ ES TU MP
</pre>
The only difference when option is 'J' is the 4<small><sup>th</sup></small> line of table is KNOQS
 
=={{header|Python}}==
{{trans|Perl 6Raku}}
<langsyntaxhighlight lang="python">from string import ascii_uppercase
from itertools import product
from re import findall
Line 353 ⟶ 2,367:
enc = encode(orig)
print "Encoded:", enc
print "Decoded:", decode(enc)</langsyntaxhighlight>
{{out}}
<pre>Original: Hide the gold in...the TREESTUMP!!!
Encoded: BM OD ZB XD NA BE KU DM UI XM MO UV IF
Decoded: HI DE TH EG OL DI NT HE TR EX ES TU MP</pre>
 
=={{header|Raku}}==
(formerly Perl 6)
<syntaxhighlight lang="raku" line># Instantiate a specific encoder/decoder.
 
sub playfair( $key,
$from = 'J',
$to = $from eq 'J' ?? 'I' !! ''
) {
 
sub canon($str) { $str.subst(/<-alpha>/,'', :g).uc.subst(/$from/,$to,:g) }
 
# Build 5x5 matrix.
my @m = canon($key ~ ('A'..'Z').join).comb.unique.map:
-> $a,$b,$c,$d,$e { [$a,$b,$c,$d,$e] }
 
# Pregenerate all forward translations.
my %ENC = gather {
# Map pairs in same row.
for @m -> @r {
for ^@r X ^@r -> (\i,\j) {
next if i == j;
take @r[i] ~ @r[j] => @r[(i+1)%5] ~ @r[(j+1)%5];
}
}
 
# Map pairs in same column.
for ^5 -> $c {
my @c = @m.map: *.[$c];
for ^@c X ^@c -> (\i,\j) {
next if i == j;
take @c[i] ~ @c[j] => @c[(i+1)%5] ~ @c[(j+1)%5];
}
}
 
# Map pairs with cross-connections.
for ^5 X ^5 X ^5 X ^5 -> (\i1,\j1,\i2,\j2) {
next if i1 == i2 or j1 == j2;
take @m[i1][j1] ~ @m[i2][j2] => @m[i1][j2] ~ @m[i2][j1];
}
}
 
# Generate reverse translations.
my %DEC = %ENC.invert;
 
return
sub enc($red) {
my @list = canon($red).comb(/(.) (.?) <?{ $1 ne $0 }>/);
~@list.map: { .chars == 1 ?? %ENC{$_~'X'} !! %ENC{$_} }
},
sub dec($black) {
my @list = canon($black).comb(/../);
~@list.map: { %DEC{$_} }
}
}
 
my (&encode,&decode) = playfair 'Playfair example';
 
my $orig = "Hide the gold in...the TREESTUMP!!!";
say " orig:\t$orig";
 
my $black = encode $orig;
say "black:\t$black";
 
my $red = decode $black;
say " red:\t$red";</syntaxhighlight>
{{out}}
<pre> orig: Hide the gold in...the TREESTUMP!!!
black: BM OD ZB XD NA BE KU DM UI XM MO UV IF
red: HI DE TH EG OL DI NT HE TR EX ES TU MP</pre>
 
=={{header|REXX}}==
Quite a bit of the REXX code deals with error checking, accepting arguments, and displaying the options used, and displaying input and output.
 
<br>For ease of viewing and comparing, the output is in capitalized digraphs (which are really ''digrams'') as well as the original input(s).
For ease of viewing and comparing, the output is in capitalized digraphs (which are really ''digrams'') as well as the original input(s).
<br>Thanks to Walter Pachl, this program is now sensitive of using a suitable ''double character'' when &nbsp; '''X''' &nbsp; is present in the cipher key.
 
Thanks to Walter Pachl, this program is now sensitive of using a suitable ''double character'' when &nbsp; '''X''' &nbsp; is present in the cipher key.
<br>Also, more thanks are due to Walter Pachl for finding that the cipher key can't contain the OMIT character.
<br>A fair amount of code was added to massage the decrypted encryption to remove doubled &nbsp; '''X'''es &nbsp; so as to match the original text
<br>(this is the ''possible text'' part of the REXX code).
<lang rexx>/*REXX program implements a PLAYFAIR cipher (encryption & decryption).*/
@abc='abcdefghijklmnopqrstuvwxyz'; @abcU=@abc /*lower and upper ABC's.*/
parse arg omit key '(' text /*TEXT is the phrase to be used. */ ;oldK=key /*save old.*/
if key =='' | key ==',' then do; key='Playfair example.'; oldK=key " ◄───using the default."; end
if omit=='' | omit==',' then omit='J' /*the "omitted" character. */
if text='' then text='Hide the gold in the tree stump!!' /*default.*/
newKey =scrub(key , 1) /*scrub old cipher key──► newKey */
newText=scrub(text ) /* " " text ──► newText*/
if newText=='' then call err 'TEXT is empty or has no letters'
if length(omit)\==1 then call err 'OMIT letter must be only one letter'
if \datatype(omit,'M') then call err 'OMIT letter must be a Latin alphabet letter.'
upper omit @abcU /*uppercase OMIT char & alphabet.*/
cant='can''t contain the "OMIT" character: ' omit
if pos(omit,newText)\==0 then call err 'TEXT' cant
if pos(omit,newKey) \==0 then call err 'cipher key' cant
fill=space(translate(@abcU,, omit), 0) /*elide OMIT char from alphabet. */
xx='X'; if omit==xx then xx='Q' /*char used for double characters*/
if length(newKey)<3 then call err 'cipher key is too short, must be ≥3 unique characters.'
fill=space(translate(fill,,newKey),0) /*remove any cipher characters. */
grid=newKey || fill /*only first 25 chars are used.*/
say 'old cipher key: ' strip(oldK) ; padL=14+2; pad=left('',padL)
say 'new cipher key: ' newKey ; padX=left('',padL,"═")'Playfair'
say ' omit char: ' omit /* [↓] lowercase of double char.*/
say ' double char: ' xx ; Lxx=translate(xx, @abc, @abcU)
say ' original text: ' strip(text) /* [↓] doubled version of Lxx. */
call show 'cleansed', newText ; LxxLxx=Lxx || Lxx
#=0 /*number of grid characters used.*/
do row =1 for 5 /*build array of individual cells*/
do col=1 for 5; #=#+1; @.row.col=substr(grid,#,1)
if row==1 then @.0.col=@.1.col
if col==5 then do; @.row.6=@.row.1; @.row.0=@.row.5; end
if row==5 then do; @.6.col=@.1.col; @.0.col=@.5.col; end
end /*col*/
end /*row*/
 
A fair amount of code was added to massage the decrypted encryption to remove doubled &nbsp; '''X'''es &nbsp; so as to match the original text
eText=.Playfair(newText, 1); call show 'encrypted' , eText
<br>(this is the &nbsp; &nbsp; ''possible text'' &nbsp; &nbsp; part of the REXX code).
pText=.Playfair(eText ); call show 'plain' , pText
<syntaxhighlight lang="rexx">/*REXX program implements a PLAYFAIR cipher (encryption and decryption). */
qText=changestr(xx ||xx,pText,Lxx) /*change doubled doublechar─►sing*/
@abc= 'abcdefghijklmnopqrstuvwxyz'; @abcU= @abc /*literals for lower and upper ABC's.*/
qText=changestr(Lxx||xx,qText,LxxLxx) /*change Xx ──► lowercase dblChar*/
parse arg omit key '(' text /*TEXT is the phrase to be used. */
qText=space(translate(qText,,xx),0) /*remove char used for "doubles."*/
upperoldKey= key qText /*reinstatesave the useold key. of upperchars*/
if length(qText)\key ==length(pText)'' | key ==',' then calldo; show key= 'possible',Playfair qTextexample.'
oldKey= key " ◄───using the default."
say ' original text: ' newText; say /*··· and show the original text.*/
end
if omit=='' | omit==',' then omit= 'J' /*the "omitted" character string. */
if text='' then text= 'Hide the gold in the tree stump!!' /*default.*/
upper omit @abcU /*uppercase OMIT characters & alphabet.*/
@cant= 'can''t contain the "OMIT" character: ' omit /*literal used in error text.*/
@uchars= 'unique characters.' /*a literal used below in an error msg.*/
newKey = scrub(key, 1) /*scrub old cipher key ──► newKey */
newText= scrub(text ) /* " " text ──► newText */
if newText=='' then call err 'TEXT is empty or has no letters.'
if length(omit)\==1 then call err 'OMIT letter must be only one letter.'
if \datatype(omit, 'M') then call err 'OMIT letter must be a Latin alphabet letter.'
if pos(omit, newText)\==0 then call err 'TEXT' @cant
if pos(omit, newKey) \==0 then call err 'cipher key' @cant
fill= space( translate(@abcU, , omit), 0) /*elide OMIT characters from alphabet. */
xx= 'X' /*character used for double characters.*/
if omit==xx then xx= 'Q' /* " " " " " */
if length(newKey)<3 then call err 'cipher key is too short, must be ≥ 3' @uchars
fill= space( translate(fill, , newKey), 0) /*remove any cipher characters. */
grid= newKey || fill /*only first 25 characters are used. */
say 'old cipher key: ' strip(oldKey)
say 'new cipher key: ' newKey
say ' omit char: ' omit
say ' double char: ' xx
say ' original text: ' strip(text)
padL= 14 + 2
call show 'cleansed', newText
#= 0 /*number of grid characters used. */
do row =1 for 5 /*build array of individual cells. */
do col=1 for 5; #= # + 1; @.row.col= substr(grid, #, 1)
if row==1 then @.0.col= @.1.col
if col==5 then do; @.row.6= @.row.1; @.row.0= @.row.5; end
if row==5 then do; @.6.col= @.1.col; @.0.col= @.5.col; end
end /*col*/
end /*row*/
pad = left('', padL)
padX= left('', padL, "═")'Playfair'
Lxx = translate(xx, @abc, @abcU) /* [↓] lowercase of double character. */
LxxLxx= Lxx || Lxx /* [↓] doubled version of Lxx. */
eText= .Playfair(newText, 1); call show 'encrypted' , eText
pText= .Playfair(eText ); call show 'plain' , pText
qText= changestr(xx || xx, pText, Lxx) /*change doubled doublechar ──► single.*/
qText= changestr(Lxx || xx, qText, LxxLxx) /*change xx ──► lowercase dblCharacter*/
qText= space( translate( qText, , xx), 0) /*remove character used for "doubles". */
upper qText /*reinstate the use of upper characters*/
if length(qText)\==length(pText) then call show 'possible', qText
say ' original text: ' newText; say /*··· and also show the original text. */
if qtext==newText then say padx 'encryption──► decryption──► encryption worked.'
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
/*──────────────────────────────────one─line subroutines───────────────────────────────*/
@@: parse arg Xrow,Xcol; return @.Xrow.Xcol
err: say; say '***error!***' arg(1); say; exit 13
LR: rowL= row(left(__, 1)); colL= _; rowR= row(right(__,1)); colR= _; return length(__)
row: ?= pos(arg(1), grid); _= (?-1) // 5 + 1; return (4+?) % 5
show: arg ,y; say; say right(arg(1) 'text: ',padL) digram(y); say pad space(y, 0); return
/*──────────────────────────────────────────────────────────────────────────────────────*/
/*──────────────────────────────────SCRUB subroutine────────────────────*/
.Playfair: arg T,encrypt; i= -1; if encrypt==1 then i= 1; $=
scrub: procedure; arg xxx,unique; xxx=space(xxx,0) /*ARG caps all args*/
$=; do jk=1 forwhile length(xxx) i==1; _= substr(xxxT,j k, 1); if _==' ' then leave
if unique_==substr(T, k+1, 1) then T= if posleft(_T,$ k)\==0 || thenLxx iterate|| substr(T, k /*unique?*/+ 1)
if datatype(_,'M') then $=$||_ /*only useend Latin letters. /*k*/
end upper /*j*/T
do j=1 by 2 to length(T); __= strip( substr(T, j, 2) )
return $
if LR()==1 then __= __ || xx; call LR /*append X or Q char, rule 1*/
/*──────────────────────────────────DIGRAM subroutine───────────────────*/
select /*rule*/
digram: procedure; parse arg x; $=; do j=1 by 2 to length(x)
when rowL==rowR then __= @@(rowL, colL+i)@@(rowR, colR+i) $=$ || substr(x,j,/*2)' '*/
when colL==colR then __= @@(rowL+i, colL )@@(rowR+i, endcolR) /*j3*/
otherwise __= @@(rowL, colR )@@(rowR, colL) /*4*/
return strip($)
end /*select*/
/*──────────────────────────────────.PLAYFAIR subroutine────────────────*/
.Playfair: arg T,encrypt; i=-1; if encrypt==1 then i=1; $= $ || $=__
do k=1 while i==1; _=substr(T,k,1); end if _==' ' then leave/*j*/
return $
if _==substr(T,k+1 ,1) then T=left(T,k) || Lxx || substr(T,k+1)
/*──────────────────────────────────────────────────────────────────────────────────────*/
end /*k*/
digram: procedure; parse arg x,,$; do j=1 by 2 to length(x)
upper T
do j=1 by 2 to length(T); __ $=strip( $ || substr(Tx, j, 2))' '
if LR()==1 then __=__ || xx; call LR /*append X or Q char, rule 1 end /*j*/
return strip($)
select
/*──────────────────────────────────────────────────────────────────────────────────────*/
when rowL==rowR then __=@@(rowL, colL+i)@@(rowR, colR+i) /*rule 2*/
scrub: procedure; arg xxx,unique; xxx= space(xxx, 0) /*ARG capitalizes all args*/
when colL==colR then __=@@(rowL+i,colL )@@(rowR+i,colR) /*rule 3*/
otherwise $=; __=@@(rowL, colR do )@@(rowR,j=1 colLfor length(xxx); /*rule 4*/_= substr(xxx, j, 1)
if unique==1 then if pos(_, $)\==0 then iterate /*is unique?*/
end /*select*/
if datatype(_, 'M') then $= $ || _ /*only use Latin letters. */
$=$ || __
end /*j*/
return $</langsyntaxhighlight>
Some older REXXes don't have a '''changestr''' bif, so one is included here ──► [[CHANGESTR.REX]].
<br><br>
'''{{out|output'''|text=&nbsp; when using the default inputs:}}
<pre>
old cipher key: Playfair example. ◄───using the default.
Line 470 ⟶ 2,566:
════════════════Playfair encryption──► decryption──► encryption worked.
</pre>
'''{{out|output'''|text=&nbsp; when using the input of: &nbsp; &nbsp; <tt> x &nbsp; stuvw &nbsp; (myteest </tt>}}
<pre>
old cipher key: stuvw
Line 493 ⟶ 2,589:
════════════════Playfair encryption──► decryption──► encryption worked.
</pre>
 
=={{header|Ruby}}==
Printing the cipher in pairs just advertises the mechanism of encoding; I've gone with the traditional grouping into sequences of five letters instead.
 
<syntaxhighlight lang="ruby">class Playfair
Size = 5
def initialize(key, missing)
@missing = missing.upcase
alphabet = ('A'..'Z').to_a.join.upcase.delete(@missing).split''
extended = key.upcase.gsub(/[^A-Z]/,'').split('') + alphabet
grid = extended.uniq[0...Size*Size].each_slice(Size).to_a
coords = {}
grid.each_with_index do |row, i|
row.each_with_index do |letter, j|
coords[letter] = [i,j]
end
end
@encode = {}
alphabet.product(alphabet).reject { |a,b| a==b }.each do |a, b|
i1, j1 = coords[a]
i2, j2 = coords[b]
if i1 == i2 then
j1 = (j1 + 1) % Size
j2 = (j2 + 1) % Size
elsif j1 == j2 then
i1 = (i1 + 1) % Size
i2 = (i2 + 1) % Size
else
j1, j2 = j2, j1
end
@encode["#{a}#{b}"] = "#{grid[i1][j1]}#{grid[i2][j2]}"
@decode = @encode.invert
end
end
 
def encode(plaintext)
plain = plaintext.upcase.gsub(/[^A-Z]/,'')
if @missing == 'J' then
plain = plain.gsub(/J/, 'I')
else
plain = plain.gsub(@missing, 'X')
end
plain = plain.gsub(/(.)\1/, '\1X\1')
if plain.length % 2 == 1 then
plain += 'X'
end
return plain.upcase.split('').each_slice(2).map do |pair|
@encode[pair.join]
end.join.split('').each_slice(5).map{|s|s.join}.join(' ')
end
 
def decode(ciphertext)
cipher = ciphertext.upcase.gsub(/[^A-Z]/,'')
return cipher.upcase.split('').each_slice(2).map do |pair|
@decode[pair.join]
end.join.split('').each_slice(5).map{|s|s.join}.join(' ')
end
end</syntaxhighlight>
 
{{Out}}
<pre>irb(main):001:0> cipher = (p=Playfair.new 'Playfair example','J').encode('hide the gold in the tree stump')
=> "BMODZ BXDNA BEKUD MUIXM MOUVI F"
irb(main):002:0> p.decode(cipher)
=> "HIDET HEGOL DINTH ETREX ESTUM P"</pre>
 
=={{header|Sidef}}==
{{trans|Raku}}
<syntaxhighlight lang="ruby">func playfair(key, from = 'J', to = (from == 'J' ? 'I' : '')) {
 
func canon(str) {
str.gsub(/[^[:alpha:]]/, '').uc.gsub(from, to)
}
 
var m = canon(key + ('A'..'Z' -> join)).chars.uniq.slices(5)
 
var :ENC = gather {
m.each { |r|
for i,j in (^r ~X ^r) {
i == j && next
take(Pair("#{r[i]}#{r[j]}", "#{r[(i+1)%5]}#{r[(j+1)%5]}"))
}
}
 
^5 -> each { |k|
var c = m.map {|a| a[k] }
for i,j in (^c ~X ^c) {
i == j && next
take(Pair("#{c[i]}#{c[j]}", "#{c[(i+1)%5]}#{c[(j+1)%5]}"))
}
}
 
cartesian([^5, ^5, ^5, ^5], {|i1,j1,i2,j2|
i1 == i2 && next
j1 == j2 && next
take(Pair("#{m[i1][j1]}#{m[i2][j2]}", "#{m[i1][j2]}#{m[i2][j1]}"))
})
}.map { (.key, .value) }...
 
var DEC = ENC.flip
 
func enc(red) {
gather {
var str = canon(red)
while (var m = (str =~ /(.)(?(?=\1)|(.?))/g)) {
take("#{m[0]}#{m[1] == '' ? 'X' : m[1]}")
}
}.map { ENC{_} }.join(' ')
}
 
func dec(black) {
canon(black).split(2).map { DEC{_} }.join(' ')
}
 
return(enc, dec)
}
 
var (encode, decode) = playfair('Playfair example')
 
var orig = "Hide the gold in...the TREESTUMP!!!"
say " orig:\t#{orig}"
 
var black = encode(orig)
say "black:\t#{black}"
 
var red = decode(black)
say " red:\t#{red}"</syntaxhighlight>
{{out}}
<pre>
orig: Hide the gold in...the TREESTUMP!!!
black: BM OD ZB XD NA BE KU DM UI XM MO UV IF
red: HI DE TH EG OL DI NT HE TR EX ES TU MP
</pre>
 
=={{header|SQL}}==
<syntaxhighlight lang="sql">
--Clean up previous run
IF EXISTS (SELECT *
FROM SYS.TYPES
WHERE NAME = 'FairPlayTable')
DROP TYPE FAIRPLAYTABLE
 
--Set Types
CREATE TYPE FAIRPLAYTABLE AS TABLE (LETTER VARCHAR(1), COLID INT, ROWID INT)
 
GO
 
--Configuration Variables
DECLARE @KEYWORD VARCHAR(25) = 'CHARLES' --Keyword for encryption
DECLARE @INPUT VARCHAR(MAX) = 'Testing Seeconqz' --Word to be encrypted
DECLARE @Q INT = 0 -- Q removed?
DECLARE @ENCRYPT INT = 1 --Encrypt?
--Setup Variables
DECLARE @WORDS TABLE
(
WORD_PRE VARCHAR(2),
WORD_POST VARCHAR(2)
)
DECLARE @T_TABLE FAIRPLAYTABLE
DECLARE @NEXTLETTER CHAR(1)
DECLARE @WORD VARCHAR(2),
@COL1 INT,
@COL2 INT,
@ROW1 INT,
@ROW2 INT,
@TMP INT
DECLARE @SQL NVARCHAR(MAX) = '',
@COUNTER INT = 1,
@I INT = 1
DECLARE @COUNTER_2 INT = 1
 
SET @INPUT = REPLACE(@INPUT, ' ', '')
SET @KEYWORD = UPPER(@KEYWORD)
 
DECLARE @USEDLETTERS VARCHAR(MAX) = ''
DECLARE @TESTWORDS VARCHAR(2),
@A INT = 0
 
WHILE @COUNTER_2 <= 5
BEGIN
WHILE @COUNTER <= 5
BEGIN
IF LEN(@KEYWORD) > 0
BEGIN
SET @NEXTLETTER = LEFT(@KEYWORD, 1)
SET @KEYWORD = RIGHT(@KEYWORD, LEN(@KEYWORD) - 1)
 
IF CHARINDEX(@NEXTLETTER, @USEDLETTERS) = 0
BEGIN
INSERT INTO @T_TABLE
SELECT @NEXTLETTER,
@COUNTER,
@COUNTER_2
 
SET @COUNTER = @COUNTER + 1
SET @USEDLETTERS = @USEDLETTERS + @NEXTLETTER
END
END
ELSE
BEGIN
WHILE 1 = 1
BEGIN
IF CHARINDEX(CHAR(64 + @I), @USEDLETTERS) = 0
AND NOT ( CHAR(64 + @I) = 'Q'
AND @Q = 1 )
AND NOT ( @Q = 0
AND CHAR(64 + @I) = 'J' )
BEGIN
SET @NEXTLETTER = CHAR(64 + @I)
SET @USEDLETTERS = @USEDLETTERS + CHAR(64 + @I)
SET @I = @I + 1
 
BREAK
END
 
SET @I = @I + 1
END
 
-- SELECT 1 AS [T]
--BREAK
INSERT INTO @T_TABLE
SELECT @NEXTLETTER,
@COUNTER,
@COUNTER_2
 
SET @COUNTER = @COUNTER + 1
END
END
 
SET @COUNTER_2 = @COUNTER_2 + 1
SET @COUNTER = 1
END
 
--Split word into Digraphs
WHILE @A < 1
BEGIN
SET @TESTWORDS = UPPER(LEFT(@INPUT, 2))
 
IF LEN(@TESTWORDS) = 1
BEGIN
SET @TESTWORDS = @TESTWORDS + 'X'
SET @A = 1
END
ELSE IF RIGHT(@TESTWORDS, 1) = LEFT(@TESTWORDS, 1)
BEGIN
SET @TESTWORDS = RIGHT(@TESTWORDS, 1) + 'X'
SET @INPUT = RIGHT(@INPUT, LEN(@INPUT) - 1)
END
ELSE
SET @INPUT = RIGHT(@INPUT, LEN(@INPUT) - 2)
 
IF LEN(@INPUT) = 0
SET @A = 1
 
INSERT @WORDS
SELECT @TESTWORDS,
''
END
 
--Start Encryption
IF @ENCRYPT = 1
BEGIN
--Loop through Digraphs amd encrypt
DECLARE WORDS_LOOP CURSOR LOCAL FORWARD_ONLY FOR
SELECT WORD_PRE
FROM @WORDS
FOR UPDATE OF WORD_POST
 
OPEN WORDS_LOOP
 
FETCH NEXT FROM WORDS_LOOP INTO @WORD
 
WHILE @@FETCH_STATUS = 0
BEGIN
--Find letter positions
SET @ROW1 = (SELECT ROWID
FROM @T_TABLE
WHERE LETTER = LEFT(@WORD, 1))
SET @ROW2 = (SELECT ROWID
FROM @T_TABLE
WHERE LETTER = RIGHT(@WORD, 1))
SET @COL1 = (SELECT COLID
FROM @T_TABLE
WHERE LETTER = LEFT(@WORD, 1))
SET @COL2 = (SELECT COLID
FROM @T_TABLE
WHERE LETTER = RIGHT(@WORD, 1))
 
--Move positions according to encryption rules
IF @COL1 = @COL2
BEGIN
SET @ROW1 = @ROW1 + 1
SET @ROW2 = @ROW2 + 1
--select 'row'
END
ELSE IF @ROW1 = @ROW2
BEGIN
SET @COL1 = @COL1 + 1
SET @COL2 = @COL2 + 1
--select 'col'
END
ELSE
BEGIN
SET @TMP = @COL2
SET @COL2 = @COL1
SET @COL1 = @TMP
--select 'reg'
END
 
IF @ROW1 = 6
SET @ROW1 = 1
 
IF @ROW2 = 6
SET @ROW2 = 1
 
IF @COL1 = 6
SET @COL1 = 1
 
IF @COL2 = 6
SET @COL2 = 1
 
--Find encrypted letters by positions
UPDATE @WORDS
SET WORD_POST = (SELECT (SELECT LETTER
FROM @T_TABLE
WHERE ROWID = @ROW1
AND COLID = @COL1)
+ (SELECT LETTER
FROM @T_TABLE
WHERE COLID = @COL2
AND ROWID = @ROW2))
WHERE WORD_PRE = @WORD
 
FETCH NEXT FROM WORDS_LOOP INTO @WORD
END
 
CLOSE WORDS_LOOP
 
DEALLOCATE WORDS_LOOP
END
--Start Decryption
ELSE
BEGIN
--Loop through Digraphs amd decrypt
DECLARE WORDS_LOOP CURSOR LOCAL FORWARD_ONLY FOR
SELECT WORD_PRE
FROM @WORDS
FOR UPDATE OF WORD_POST
 
OPEN WORDS_LOOP
 
FETCH NEXT FROM WORDS_LOOP INTO @WORD
 
WHILE @@FETCH_STATUS = 0
BEGIN
--Find letter positions
SET @ROW1 = (SELECT ROWID
FROM @T_TABLE
WHERE LETTER = LEFT(@WORD, 1))
SET @ROW2 = (SELECT ROWID
FROM @T_TABLE
WHERE LETTER = RIGHT(@WORD, 1))
SET @COL1 = (SELECT COLID
FROM @T_TABLE
WHERE LETTER = LEFT(@WORD, 1))
SET @COL2 = (SELECT COLID
FROM @T_TABLE
WHERE LETTER = RIGHT(@WORD, 1))
 
--Move positions according to encryption rules
IF @COL1 = @COL2
BEGIN
SET @ROW1 = @ROW1 - 1
SET @ROW2 = @ROW2 - 1
--select 'row'
END
ELSE IF @ROW1 = @ROW2
BEGIN
SET @COL1 = @COL1 - 1
SET @COL2 = @COL2 - 1
--select 'col'
END
ELSE
BEGIN
SET @TMP = @COL2
SET @COL2 = @COL1
SET @COL1 = @TMP
--select 'reg'
END
 
IF @ROW1 = 0
SET @ROW1 = 5
 
IF @ROW2 = 0
SET @ROW2 = 5
 
IF @COL1 = 0
SET @COL1 = 5
 
IF @COL2 = 0
SET @COL2 = 5
 
--Find decrypted letters by positions
UPDATE @WORDS
SET WORD_POST = (SELECT (SELECT LETTER
FROM @T_TABLE
WHERE ROWID = @ROW1
AND COLID = @COL1)
+ (SELECT LETTER
FROM @T_TABLE
WHERE COLID = @COL2
AND ROWID = @ROW2))
WHERE WORD_PRE = @WORD
 
FETCH NEXT FROM WORDS_LOOP INTO @WORD
END
 
CLOSE WORDS_LOOP
 
DEALLOCATE WORDS_LOOP
END
 
--Output
DECLARE WORDS CURSOR LOCAL FAST_FORWARD FOR
SELECT WORD_POST
FROM @WORDS
 
OPEN WORDS
 
FETCH NEXT FROM WORDS INTO @WORD
 
WHILE @@FETCH_STATUS = 0
BEGIN
SET @SQL = @SQL + @WORD + ' '
 
FETCH NEXT FROM WORDS INTO @WORD
END
 
CLOSE WORDS
 
DEALLOCATE WORDS
 
SELECT @SQL
 
--Cleanup
IF EXISTS (SELECT *
FROM SYS.TYPES
WHERE NAME = 'FairPlayTable')
DROP TYPE FAIRPLAYTABLE
</syntaxhighlight>
 
=={{header|Tcl}}==
 
{{works with|Tcl|8.6}}
<langsyntaxhighlight lang="tcl">package require TclOO
 
oo::class create Playfair {
variable grid lookup excluder
constructor {{keyword "PLAYFAIR EXAMPLE"} {exclude "J"}} {
# Tweaking according to exact operation mode
if {$exclude eq "J"} {
set excluder "J I"
} else {
set excluder [list $exclude ""]
}
}
 
# Clean up the keyword source
set keys [my Clean [append keyword "ABCDEFGHIJKLMNOPQRSTUVWXYZ"]]
 
# Generate the encoding grid
set grid [lrepeat 5 [lrepeat 5 ""]]
set idx -1
for {set i 0} {$i < 5} {incr i} {for {set j 0} {$j < 5} {} {
if {![info exist lookup([set c [lindex $keys [incr idx]]])]} {
lset grid $i $j $c
set lookup($c) [list $i $j]
incr j
}
}}
}}
 
# Sanity check
if {[array size lookup] != 25} {
error "failed to build encoding table correctly"
}
}
}
 
# Worker to apply a consistent cleanup/split rule
method Clean {str} {
set str [string map $excluder [string toupper $str]]
split [regsub -all {[^A-Z]} $str ""] ""
}
 
# These public methods are implemented by a single non-public method
forward encode my Transform 1
forward decode my Transform -1
 
# The application of the Playfair cypher transform
method Transform {direction message} {
# Split message into true digraphs
foreach c [my Clean $message] {
if {![info exists lookup($c)]} continue
if {![info existexists c0]} {
set c0 $c
lappend digraphs $c0 [expr {$c0 eq $c ? "X" : $c}]
} else {
unset c0
} else if {$c0 ne $c} {
lappend digraphs $c0 $c
set c0 $c
unset c0
}
} else {
}
lappend digraphs $c0 "X"
if {[info exist c0]} {
set c0 $c
lappend digraphs $c0 "Z"
}
}
}
 
}
# Encode the digraphs
if {[info exists c0]} {
set result ""
foreach {a b} $ lappend digraphs {$c0 "Z"
lassign $lookup($a) ai aj }
lassign $lookup($b) bi bj
if {$ai == $bi} {
set aj [expr {($aj + $direction) % 5}]
set bj [expr {($bj + $direction) % 5}]
} elseif {$aj == $bj} {
set ai [expr {($ai + $direction) % 5}]
set bi [expr {($bi + $direction) % 5}]
} else {
set tmp $aj
set aj $bj
set bj $tmp
}
lappend result [lindex $grid $ai $aj][lindex $grid $bi $bj]
}
 
# Encode the digraphs
# Real use would be: return [join $result ""]
return $ set result ""
foreach {a b} $digraphs {
lassign $lookup($a) ai aj
lassign $lookup($b) bi bj
if {$ai == $bi} {
set aj [expr {($aj + $direction) % 5}]
set bj [expr {($bj + $direction) % 5}]
} elseif {$aj == $bj} {
set ai [expr {($ai + $direction) % 5}]
set bi [expr {($bi + $direction) % 5}]
} else {
set tmp $aj
set aj $bj
set bj $tmp
}
lappend result [lindex $grid $ai $aj][lindex $grid $bi $bj]
}
# Real use would be: return [join $result ""]
return $result
}
}</langsyntaxhighlight>
Demonstrating:
<langsyntaxhighlight lang="tcl">Playfair create cypher "Playfair Example"
set plaintext "Hide the gold in...the TREESTUMP!!!"
set encoded [cypher encode $plaintext]
Line 584 ⟶ 3,135:
puts "Original: $plaintext"
puts "Encoded: $encoded"
puts "Decoded: $decoded"</langsyntaxhighlight>
{{out}}
<pre>
Original: Hide the gold in...the TREESTUMP!!!
Encoded: BM OD ZB XD NA BE KU DM UI XM KZMO ZRUV FTIF
Decoded: HI DE TH EG OL DI NT HE TR EX STES UMTU PZMP
</pre>
 
=={{header|VBA}}==
<syntaxhighlight lang="vb">
Option Explicit
 
Private Type Adress
Row As Integer
Column As Integer
End Type
 
Private myTable() As String
 
Sub Main()
Dim keyw As String, boolQ As Boolean, text As String, test As Long
Dim res As String
keyw = InputBox("Enter your keyword : ", "KeyWord", "Playfair example")
If keyw = "" Then GoTo ErrorHand
Debug.Print "Enter your keyword : " & keyw
boolQ = MsgBox("Ignore Q when buiding table y/n : ", vbYesNo) = vbYes
Debug.Print "Ignore Q when buiding table y/n : " & IIf(boolQ, "Y", "N")
Debug.Print ""
Debug.Print "Table : "
myTable = CreateTable(keyw, boolQ)
On Error GoTo ErrorHand
test = UBound(myTable)
On Error GoTo 0
text = InputBox("Enter your text", "Encode", "hide the gold in the TRRE stump")
If text = "" Then GoTo ErrorHand
Debug.Print ""
Debug.Print "Text to encode : " & text
Debug.Print "-------------------------------------------------"
res = Encode(text)
Debug.Print "Encoded text is : " & res
res = Decode(res)
Debug.Print "Decoded text is : " & res
text = InputBox("Enter your text", "Encode", "hide the gold in the TREE stump")
If text = "" Then GoTo ErrorHand
Debug.Print ""
Debug.Print "Text to encode : " & text
Debug.Print "-------------------------------------------------"
res = Encode(text)
Debug.Print "Encoded text is : " & res
res = Decode(res)
Debug.Print "Decoded text is : " & res
Exit Sub
ErrorHand:
Debug.Print "error"
End Sub
 
Private Function CreateTable(strKeyword As String, Q As Boolean) As String()
Dim r As Integer, c As Integer, temp(1 To 5, 1 To 5) As String, t, cpt As Integer
Dim strT As String, coll As New Collection
Dim s As String
 
strKeyword = UCase(Replace(strKeyword, " ", ""))
If Q Then
If InStr(strKeyword, "J") > 0 Then
Debug.Print "Your keyword isn't available with your choice : Not Q (==> J) !"
Exit Function
End If
Else
If InStr(strKeyword, "Q") > 0 Then
Debug.Print "Your keyword isn't available with your choice : Q (==> Not J) !"
Exit Function
End If
End If
strT = IIf(Not Q, "ABCDEFGHIKLMNOPQRSTUVWXYZ", "ABCDEFGHIJKLMNOPRSTUVWXYZ")
t = Split(StrConv(strKeyword, vbUnicode), Chr(0))
For c = LBound(t) To UBound(t) - 1
strT = Replace(strT, t(c), "")
On Error Resume Next
coll.Add t(c), t(c)
On Error GoTo 0
Next
strKeyword = vbNullString
For c = 1 To coll.Count
strKeyword = strKeyword & coll(c)
Next
t = Split(StrConv(strKeyword & strT, vbUnicode), Chr(0))
c = 1: r = 1
For cpt = LBound(t) To UBound(t) - 1
temp(r, c) = t(cpt)
s = s & " " & t(cpt)
c = c + 1
If c = 6 Then c = 1: r = r + 1: Debug.Print " " & s: s = ""
Next
CreateTable = temp
End Function
 
Private Function Encode(s As String) As String
Dim i&, t() As String, cpt&
s = UCase(Replace(s, " ", ""))
'insert "X"
For i = 1 To Len(s) - 1
If Mid(s, i, 1) = Mid(s, i + 1, 1) Then s = Left(s, i) & "X" & Right(s, Len(s) - i)
Next
'Do the pairs
For i = 1 To Len(s) Step 2
ReDim Preserve t(cpt)
t(cpt) = Mid(s, i, 2)
cpt = cpt + 1
Next i
If Len(t(UBound(t))) = 1 Then t(UBound(t)) = t(UBound(t)) & "X"
Debug.Print "[the pairs : " & Join(t, " ") & "]"
'swap the pairs
For i = LBound(t) To UBound(t)
t(i) = SwapPairsEncoding(t(i))
Next
Encode = Join(t, " ")
End Function
 
Private Function SwapPairsEncoding(s As String) As String
Dim r As Integer, c As Integer, d1 As String, d2 As String, Flag As Boolean
Dim addD1 As Adress, addD2 As Adress, resD1 As Adress, resD2 As Adress
d1 = Left(s, 1): d2 = Right(s, 1)
For r = 1 To 5
For c = 1 To 5
If d1 = myTable(r, c) Then addD1.Row = r: addD1.Column = c
If d2 = myTable(r, c) Then addD2.Row = r: addD2.Column = c
If addD1.Row <> 0 And addD2.Row <> 0 Then Flag = True: Exit For
Next
If Flag Then Exit For
Next
Select Case True
Case addD1.Row = addD2.Row And addD1.Column <> addD2.Column
'same row, different columns
resD1.Column = IIf(addD1.Column + 1 = 6, 1, addD1.Column + 1)
resD2.Column = IIf(addD2.Column + 1 = 6, 1, addD2.Column + 1)
SwapPairsEncoding = myTable(addD1.Row, resD1.Column) & myTable(addD2.Row, resD2.Column)
Case addD1.Row <> addD2.Row And addD1.Column = addD2.Column
'same columns, different rows
resD1.Row = IIf(addD1.Row + 1 = 6, 1, addD1.Row + 1)
resD2.Row = IIf(addD2.Row + 1 = 6, 1, addD2.Row + 1)
SwapPairsEncoding = myTable(resD1.Row, addD1.Column) & myTable(resD2.Row, addD2.Column)
Case addD1.Row <> addD2.Row And addD1.Column <> addD2.Column
'different rows, different columns
resD1.Row = addD1.Row
resD2.Row = addD2.Row
resD1.Column = addD2.Column
resD2.Column = addD1.Column
SwapPairsEncoding = myTable(resD1.Row, resD1.Column) & myTable(resD2.Row, resD2.Column)
End Select
End Function
 
Private Function Decode(s As String) As String
Dim t, i&, j&, e&
t = Split(s, " ")
e = UBound(t) - 1
'swap the pairs
For i = LBound(t) To UBound(t)
t(i) = SwapPairsDecoding(CStr(t(i)))
Next
'remove "X"
For i = LBound(t) To e
If Right(t(i), 1) = "X" And Left(t(i), 1) = Left(t(i + 1), 1) Then
t(i) = Left(t(i), 1) & Left(t(i + 1), 1)
For j = i + 1 To UBound(t) - 1
t(j) = Right(t(j), 1) & Left(t(j + 1), 1)
Next j
If Right(t(j), 1) = "X" Then
ReDim Preserve t(j - 1)
Else
t(j) = Right(t(j), 1) & "X"
End If
ElseIf Left(t(i + 1), 1) = "X" And Right(t(i), 1) = Right(t(i + 1), 1) Then
For j = i + 1 To UBound(t) - 1
t(j) = Right(t(j), 1) & Left(t(j + 1), 1)
Next j
If Right(t(j), 1) = "X" Then
ReDim Preserve t(j - 1)
Else
t(j) = Right(t(j), 1) & "X"
End If
End If
Next
Decode = Join(t, " ")
End Function
 
Private Function SwapPairsDecoding(s As String) As String
Dim r As Integer, c As Integer, d1 As String, d2 As String, Flag As Boolean
Dim addD1 As Adress, addD2 As Adress, resD1 As Adress, resD2 As Adress
d1 = Left(s, 1): d2 = Right(s, 1)
For r = 1 To 5
For c = 1 To 5
If d1 = myTable(r, c) Then addD1.Row = r: addD1.Column = c
If d2 = myTable(r, c) Then addD2.Row = r: addD2.Column = c
If addD1.Row <> 0 And addD2.Row <> 0 Then Flag = True: Exit For
Next
If Flag Then Exit For
Next
Select Case True
Case addD1.Row = addD2.Row And addD1.Column <> addD2.Column
'same row, different columns
resD1.Column = IIf(addD1.Column - 1 = 0, 5, addD1.Column - 1)
resD2.Column = IIf(addD2.Column - 1 = 0, 5, addD2.Column - 1)
SwapPairsDecoding = myTable(addD1.Row, resD1.Column) & myTable(addD2.Row, resD2.Column)
Case addD1.Row <> addD2.Row And addD1.Column = addD2.Column
'same columns, different rows
resD1.Row = IIf(addD1.Row - 1 = 0, 5, addD1.Row - 1)
resD2.Row = IIf(addD2.Row - 1 = 0, 5, addD2.Row - 1)
SwapPairsDecoding = myTable(resD1.Row, addD1.Column) & myTable(resD2.Row, addD2.Column)
Case addD1.Row <> addD2.Row And addD1.Column <> addD2.Column
'different rows, different columns
resD1.Row = addD1.Row
resD2.Row = addD2.Row
resD1.Column = addD2.Column
resD2.Column = addD1.Column
SwapPairsDecoding = myTable(resD1.Row, resD1.Column) & myTable(resD2.Row, resD2.Column)
End Select
End Function</syntaxhighlight>
{{out}}
<pre>Enter your keyword : Playfair example
Ignore Q when buiding table y/n : N
 
Table :
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
 
Text to encode : hide the gold in the TRRE stump
-------------------------------------------------
[the pairs : HI DE TH EG OL DI NT HE TR XR ES TU MP]
Encoded text is : BM OD ZB XD NA BE KU DM UI ME MO UV IF
Decoded text is : HI DE TH EG OL DI NT HE TR RE ST UM PX
 
Text to encode : hide the gold in the TREE stump
-------------------------------------------------
[the pairs : HI DE TH EG OL DI NT HE TR EX ES TU MP]
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 EE ST UM PX</pre>
 
=={{header|V (Vlang)}}==
{{trans|Go}}
<syntaxhighlight lang="v (vlang)">import os
import strings
type PlayfairOption = int
const (
no_q = 0
i_equals_j = 1
)
struct Playfair {
mut:
keyword string
pfo PlayfairOption
table [5][5]u8
}
fn (mut p Playfair) init() {
// Build table.
mut used := [26]bool{} // all elements false
if p.pfo == no_q {
used[16] = true // Q used
} else {
used[9] = true // J used
}
alphabet := p.keyword.to_upper() + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
for i, j, k := 0, 0, 0; k < alphabet.len; k++ {
c := alphabet[k]
if c < 'A'[0] || c > 'Z'[0] {
continue
}
d := int(c - 65)
if !used[d] {
p.table[i][j] = c
used[d] = true
j++
if j == 5 {
i++
if i == 5 {
break // table has been filled
}
j = 0
}
}
}
}
fn (p Playfair) get_clean_text(pt string) string {
// Ensure everything is upper case.
plain_text := pt.to_upper()
// Get rid of any non-letters and insert X between duplicate letters.
mut clean_text := strings.new_builder(128)
// Safe to assume null u8 won't be present in plain_text.
mut prev_byte := `\000`
for i in 0..plain_text.len {
mut next_byte := plain_text[i]
// It appears that Q should be omitted altogether if NO_Q option is specified;
// we assume so anyway.
if next_byte < 'A'[0] || next_byte > 'Z'[0] || (next_byte == 'Q'[0] && p.pfo == no_q) {
continue
}
// If i_equals_j option specified, replace J with I.
if next_byte == 'J'[0] && p.pfo == i_equals_j {
next_byte = 'I'[0]
}
if next_byte != prev_byte {
clean_text.write_u8(next_byte)
} else {
clean_text.write_u8('X'[0])
clean_text.write_u8(next_byte)
}
prev_byte = next_byte
}
l := clean_text.len
if l%2 == 1 {
// Dangling letter at end so add another letter to complete digram.
if clean_text.str()[l-1] != 'X'[0] {
clean_text.write_u8('X'[0])
} else {
clean_text.write_u8('Z'[0])
}
}
return clean_text.str()
}
fn (p Playfair) find_byte(c u8) (int, int) {
for i in 0..5 {
for j in 0..5 {
if p.table[i][j] == c {
return i, j
}
}
}
return -1, -1
}
fn (p Playfair) encode(plain_text string) string {
clean_text := p.get_clean_text(plain_text)
mut cipher_text := strings.new_builder(128)
l := clean_text.len
for i := 0; i < l; i += 2 {
row1, col1 := p.find_byte(clean_text[i])
row2, col2 := p.find_byte(clean_text[i+1])
if row1 == row2{
cipher_text.write_u8(p.table[row1][(col1+1)%5])
cipher_text.write_u8(p.table[row2][(col2+1)%5])
} else if col1 == col2{
cipher_text.write_u8(p.table[(row1+1)%5][col1])
cipher_text.write_u8(p.table[(row2+1)%5][col2])
} else {
cipher_text.write_u8(p.table[row1][col2])
cipher_text.write_u8(p.table[row2][col1])
}
if i < l-1 {
cipher_text.write_u8(' '[0])
}
}
return cipher_text.str()
}
fn (p Playfair) decode(cipher_text string) string {
mut decoded_text := strings.new_builder(128)
l := cipher_text.len
// cipher_text will include spaces so we need to skip them.
for i := 0; i < l; i += 3 {
row1, col1 := p.find_byte(cipher_text[i])
row2, col2 := p.find_byte(cipher_text[i+1])
if row1 == row2 {
mut temp := 4
if col1 > 0 {
temp = col1 - 1
}
decoded_text.write_u8(p.table[row1][temp])
temp = 4
if col2 > 0 {
temp = col2 - 1
}
decoded_text.write_u8(p.table[row2][temp])
} else if col1 == col2 {
mut temp := 4
if row1 > 0 {
temp = row1 - 1
}
decoded_text.write_u8(p.table[temp][col1])
temp = 4
if row2 > 0 {
temp = row2 - 1
}
decoded_text.write_u8(p.table[temp][col2])
} else {
decoded_text.write_u8(p.table[row1][col2])
decoded_text.write_u8(p.table[row2][col1])
}
if i < l-1 {
decoded_text.write_u8(' '[0])
}
}
return decoded_text.str()
}
fn (p Playfair) print_table() {
println("The table to be used is :\n")
for i in 0..5 {
for j in 0..5 {
print("${p.table[i][j].ascii_str()} ")
}
println('')
}
}
fn main() {
keyword := os.input("Enter Playfair keyword : ")
mut ignore_q := ''
for ignore_q != "y" && ignore_q != "n" {
ignore_q = os.input("Ignore Q when building table y/n : ").to_lower()
}
mut pfo := no_q
if ignore_q == "n" {
pfo = i_equals_j
}
mut table := [5][5]u8{}
mut pf := Playfair{keyword, pfo, table}
pf.init()
pf.print_table()
plain_text := os.input("\nEnter plain text : ")
encoded_text := pf.encode(plain_text)
println("\nEncoded text is : $encoded_text")
decoded_text := pf.decode(encoded_text)
println("Deccoded text is : $decoded_text")
}</syntaxhighlight>
 
{{out}}
Sample run:
<pre>
Enter Playfair keyword : Playfair example
Ignore Q when building 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
Deccoded text is : HI DE TH EG OL DI NT HE TR EX ES TU MP
</pre>
 
=={{header|Wren}}==
{{trans|Kotlin}}
{{libheader|Wren-dynamic}}
{{libheader|Wren-str}}
{{libheader|Wren-iterate}}
{{libheader|Wren-ioutil}}
<syntaxhighlight lang="wren">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)")</syntaxhighlight>
 
{{out}}
<pre>
Enter Playfair keyword : Playfair example
Ignore Q when building_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|zkl}}==
<syntaxhighlight lang="zkl">fcn genKeyTable(key,deadChr){ // deadChr=="Q" or "J"
deadChr=deadChr.toUpper();
key=key.toUpper().unique() - " " - deadChr;
return(key + (["A".."Z"].pump(String) - deadChr - key), deadChr);
}</syntaxhighlight>
<syntaxhighlight lang="zkl">fcn playfair(text,keytable){ // text is a-z only
keyTable,deadChr:=keytable;
text=text.toUpper();
text-=text - keyTable; // remove unencodable characters
if(deadChr=="Q") text-=deadChr; else text=text.replace("J","I");
 
text=text.pump(String,T(Void.Read,1,False),
fcn(a,b=""){ if(a==b) a+"X"+b else a+b });
if(text.len().isOdd) text+="Z";
 
row:='wrap(c){ keyTable.index(c)/5 };
col:='wrap(c){ keyTable.index(c)%5 };
ltrRight:='wrap(c){ keyTable[(keyTable.index(c) + 1)%25] };
ltrBelow:='wrap(c){ keyTable[(keyTable.index(c) + 5)%25] };
ltrAt:='wrap(r,c) { keyTable[r*5 + c] };
 
text.pump(String, Void.Read, //-->digraph
'wrap(a,b){
if((ra:=row(a))==(rb:=row(b))) return(ltrRight(a) + ltrRight(b));
if((ca:=col(a))==(cb:=col(b))) return(ltrBelow(a) + ltrBelow(b));
return(ltrAt(ra,cb) + ltrAt(rb,ca));
})
.pump(String,Void.Read,"".create.fp(" ")).strip(); // insert blanks
}</syntaxhighlight>
<syntaxhighlight lang="zkl">fcn decodePF(text,keyTable){
keyTable,_=keyTable;
text-=" ";
row:='wrap(c){ keyTable.index(c)/5 };
col:='wrap(c){ keyTable.index(c)%5 };
ltrLeft:='wrap(c){ keyTable[(keyTable.index(c) - 1)%25] };
ltrUp:='wrap(c){ n:=keyTable.index(c) - 5; if(n<0)n+=25; keyTable[n%25] };
ltrAt:='wrap(r,c){ keyTable[r*5 + c] };
text.pump(String,Void.Read, //-->digraph
'wrap(a,b){
if((ra:=row(a))==(rb:=row(b))) return(ltrLeft(a) + ltrLeft(b));
if((ca:=col(a))==(cb:=col(b))) return(ltrUp(a) + ltrUp(b));
return(ltrAt(ra,cb) + ltrAt(rb,ca));
})
.pump(String,Void.Read,"".create.fp(" ")).strip(); // insert blanks
}
</syntaxhighlight>
<syntaxhighlight lang="zkl">msg:="Hide the gold in the tree stump!!!";
keyTable:=genKeyTable("playfair example");
msg.println();
e:=playfair(msg,keyTable); e.println();
decodePF(e,keyTable).println();
playfair("XX",keyTable).println() : decodePF(_,keyTable).println();</syntaxhighlight>
{{out}}
<pre>
Hide the gold in the tree stump!!!
BM OD ZB XD NA BE KU DM UI XM MO UV IF
HI DE TH EG OL DI NT HE TR EX ES TU MP
MM MW
XX XZ
</pre>
9,487

edits