Skip to content

Instantly share code, notes, and snippets.

@leontabak
Created October 8, 2021 14:19
Show Gist options
  • Save leontabak/02671ffe181429efef7e39d279dc98d1 to your computer and use it in GitHub Desktop.
Save leontabak/02671ffe181429efef7e39d279dc98d1 to your computer and use it in GitHub Desktop.
Solve one part of Playfair Cipher problem in Scala.
// This is an effort to solve a problem that
// arose in the course of an effort to write
// a program that encrypts a message using
// the Playfair Cipher.
// It divides the plain text into groups of
// 2 letters (digrams), ensuring that no
// diagram contains 2 identical letters.
// I have used grouped(), indexWhere(), reduce(),
// splitAt(), and recursion.
object Repeats extends App {
val s0 = "SEETHEGEESEANDTHEMOOSETHENFLEEORFREEZE"
//val s0 = "AACDEFGH"
//val s0 = "ILOOKFREELY"
println(s"s0 = $s0")
println()
// f() is not a recursive function
def f(noRepeats: String, unsure: String): (String, String) = {
// We are going to divide a string into 2-character
// strings, so make sure length of string is even.
val maybeRepeats = if( unsure.length % 2 == 0) unsure else
unsure + "X"
var result = (noRepeats, maybeRepeats)
// Divide string into pairs of letters
val s1 = maybeRepeats.grouped(2).toVector
// Find index of first pair of letters (if any)
// that contains 2 identical letters
// Need to allow repeated X's or infinite recursion
// occurs
val index = s1.indexWhere((s: String) => (s(0) == s(1)) &&
(s(0) != 'X'))
// Set j to that index if a pair with repeated
// letters was found, set j to the number of
// pairs otherwise
val j = if (index >= 0) index else s1.length
// Create 2 smaller Vectors.
// * prefix contains pairs with no-identical letters
// * suffix contains the first pair with identical
// letters plus all pairs that follow
val (prefix, suffix) = s1.splitAt(j)
//println( s"f:prefix = $prefix")
//println( s"f:suffix = $suffix")
//println( s"f:s1 = $s1")
// Convert the Vector (a sequence of pairs
// of letters to a single string.
val donePart = if( prefix.size > 0)
noRepeats + prefix.reduce(_ + _) else noRepeats
if (suffix.size > 0) {
//println( "\n -if- \n")
// Get that first pair of identical letters
val repeatedLetters = suffix(0)
// Make a single string out of all of the
// remaining pairs in suffix.
var remainder = ""
if( suffix.size > 1) {
val tail = suffix.slice(1, suffix.size)
remainder += tail.reduce(_ + _)
} // if
// Make a new pair that contains the first of the
// repeated letters and "X".
// Tack it on to the end of the Vector that contains
// only pairs with no repeated letters.
val allDone = (donePart + repeatedLetters(0) + "X")
// Pre-append the second of the repeated letters
// to the Vector that might still contain other
// pairs with repeated letters.
val moreToDo = repeatedLetters(1) + remainder
result = (allDone, moreToDo)
} // if
else {
// Did not find any pairs with repeated letters.
//println("\n -else- \n")
result = (donePart, "")
} // else
//println()
//println( s"f:noRepeats = ${result._1}")
//println( s"f:unsure = ${result._2}")
//println()
result
} // end of f()
// gHelper() is a recursive function
// it calls f() and itself
def gHelper( noRepeats:String, unsure:String ):String = {
//println( s"gHelper:noRepeats = ($noRepeats)")
//println( s"gHelper:unsure = ($unsure)" )
// p means "prefix"---no 2 letter groups with repeats
// s means "suffix"---part of message still unchecked
val (p, s) = f(noRepeats, unsure)
//println( s"gHelper:p = ($p)" )
//println( s"gHelper:s = ($s)" )
//println()
if( s.length == 0) p else gHelper(p, s)
} // end of g()
// g is not a recursive function
// it calls gHelper() to get things
// started
def g(message:String):String = gHelper("", message)
val z = g(s0)
println( z )
val w = z.grouped(2).toVector
println( w )
} // Repeats
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment