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}"
Output:
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