substitution_cipher.sf 1.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. #!/usr/bin/ruby
  2. # A simple substitution cipher, given a key that maps each letter to a different letter.
  3. # The position of the letters in the key are used for mapping.
  4. # And also the letters in the key are the letters allowed in the message.
  5. # See also:
  6. # https://rosettacode.org/wiki/Substitution_cipher
  7. class SubstitutionCipher(Array key) {
  8. has keylookup = Hash(key.kv.map{.flip}.flat...)
  9. has num2alpha = Hash(key.sort.kv.flat...)
  10. has alpha2num = num2alpha.flip
  11. method encode(String s) {
  12. var r = ""
  13. s.each {|c|
  14. r += (alpha2num.has(c) ? key[alpha2num{c}] : " ")
  15. }
  16. return r
  17. }
  18. method decode(String s) {
  19. var r = ""
  20. s.each {|c|
  21. r += (keylookup.has(c) ? num2alpha{keylookup{c}} : " ")
  22. }
  23. return r
  24. }
  25. }
  26. # Allow only lowercase a..z
  27. var alpha = ['a'..'z'].map{.to_a}.flat
  28. # Allow digits, lower/upper case a..z and space
  29. # var alpha = [0..9, 'A'..'Z', 'a'..'z', ' '].map{.to_a}.flat
  30. var key = alpha.shuffle
  31. var obj = SubstitutionCipher(key)
  32. say "Encoding with key: #{key.join.dump}"
  33. with ("the quick brown fox jumps over the lazy dog who barks very loudly") { |s|
  34. var enc = obj.encode(s)
  35. var dec = obj.decode(enc)
  36. print <<-EOT
  37. Original: #{s.dump}
  38. -> Encoded: #{enc.dump}
  39. -> Decoded: #{dec.dump}
  40. EOT
  41. assert_eq(dec, s)
  42. }