#!/usr/bin/ruby # ## https://rosettacode.org/wiki/Playfair_cipher # 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}" assert_eq(black, "BM OD ZB XD NA BE KU DM UI XM MO UV IF") assert_eq(red, "HI DE TH EG OL DI NT HE TR EX ES TU MP")