78 lines
2.1 KiB
APL
78 lines
2.1 KiB
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
|