I've worked out a functioning Vigenère encryption in Scala, and while it doesn't seem like my code is too hideous, I'm sure I could make it more functional and Scala-esque. Primarily, it seems like:

  1. I've made the full key with a for-expression / zipWithIndex, I'm wondering if this is the best way to do this though. Would it be better to do this inside the encipher() function? Using an anonymous function? The way I have it now works, but I'm curious if there's a way to do so that'd be more in line with Scala best practices.
  2. The actual encryption portion, specifically the output for case (c, i), is sort of messy/convoluted, and it seems like there might be a better way to do it.

Of course, I'll be grateful for any feedback. Definitely still getting my feet wet with Scala, and any help getting into a more functional state of mind would be appreciated.

object Vigenere {

// alphabet for use throughout object
private val alphabet = ('A' to 'Z').toList
//empty array to be filled with fillTabula() function
private var tabulaRecta = Array.ofDim[Char](26, 26)

/* fills the tabula recta array
** creates 26 rows of alphabets, each alphabet shifted
** left by one letter each iteration */
def fillTabula() = {
    for (row <- 0 to 25) {
        for (col <- 0 to 25) {
            tabulaRecta(row)(col) = alphabet((row + col) % 26)

/* create the full key by repeating the key until its as long
** as the plaintext. */
def makeFullkey(key: String, text:String): String = {
    val fkey = for (c <- text.zipWithIndex) yield c match {
            case (c, i) => key(i % key.length)
        return fkey.mkString

def encipher(key: String, text:String): String = {
    // fill the tabula recta
    val fkey = makeFullkey(key, text)

    /* to encipher, zip the plaintext to return each letter with
    ** its index. if it's a space, just add space to ciphertext.
    ** if it's not a space, find the corresponding row in the 
    ** tabula recta, then go to the appropriate column to
    ** return the ciphertext character.
    ** the second case here is a mess, there's got to be a nicer way. */ 

    val ciphertext = for (c <- text.zipWithIndex) yield c match {
        case (' ', _) => ' '
        case (c, i)   => tabulaRecta(alphabet.indexOf(fkey(i)))(alphabet.indexOf(c))
    return ciphertext.mkString

def main(args: Array[String]) {
    val Array(text, key) = args

    println("Plaintext: " + text)
    println("Key: " + key)
    println("Ciphertext: " + encipher(key.toUpperCase, text.toUpperCase))


Edit: I realized that I could make the fullkey using zipWithIndex as well, and also found a better place to use toUpperCase. I've changed the code and updated my question accordingly.


1 Answer 1


I'm not a scala/fp expert but here is my 2 cents.

Your code reads very much like you have read the definition on wikipedia and translated it into scala. As the wikipedia definition is written as a human implemented algorithm you end up with a very procedural approach.

A few specific things:

  • tabulaRecta - this is constant, making it a var is a massive code smell
  • makeFullkey - you use zipWithIndex but don't use c, just use index
  • why can't tabulaRecta be a function?
  • why create a fullKey - can't you compute the key char as a function?
  • \$\begingroup\$ Hmm, I honestly have no idea how I'd go about making tabulaRecta into a function at this point, I'd certainly prefer it being a val too. I'm sure you're right about the fullKey thing too. I used zipWithIndex on the fullKey so as to avoid using an accumulating counter variable, but I'm sure there's a better way to do that too. Thanks for giving me some stuff to think about! \$\endgroup\$
    – djc
    Jul 29, 2015 at 16:01
  • \$\begingroup\$ Let me know if want more help, I can post some actual code as well. I thought it best just to give you pointers to start with. \$\endgroup\$
    – brain
    Jul 29, 2015 at 16:37
  • \$\begingroup\$ Appreciate it! I'll see what I can come up with and come back if I can't figure anything out. \$\endgroup\$
    – djc
    Jul 29, 2015 at 16:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.