FCC Bonfire Series 148: Caesars Cipher

FreeCodeCamp has recently added a few more challenges to the site. One of them is Caesars Cipher. This bonfire will have us write a function that mimics the ages old encryption method allegedly used by Romans back in the day.

It’s one of the simplest and oldest encryption methods, and works by replacing each character in a word or sentence with another one down the alphabet (based on a shift amount). For this exercise, we are told to use a shift of 13. Let me show you an example using the word dog and a shift of three.

  • d -> e, f, g
  • o -> p, q, r
  • g -> h, i, j

If shifted by three, we get the following string: grj. Keep in mind that we could get strings such as: what. Let’s use a shift of 5:

  • w -> x, y, z, a, b
  • h -> i, j, k, l, m
  • a -> b, c, d, e, f
  • t -> u, v, w, x, y

Notice how shifting w by 5 will wrap around the alphabet and set that character to b. The end result is bmfy.

Let’s get started and create a function that automates this process. We know from previous exercises that we can use String.prototype.charCodeAt() to get the character code for any given letter and String.fromCharCode() to turn a character code back into it’s letter counterpart.

Let’s see an example:

var myLetter = 'a';

var charCode = myLetter.charCodeAt(0); // We get the character code at index 0

console.log(charCode); // 97
console.log(String.fromCharCode(charCode)); // 'a'

 

This poses a little problem though, uppercase characters (‘A’) and  their lowercase counterparts each have their own character code:

'A'.charCodeAt(0); //-> 65
'a'.charCodeAt(0); //-> 97

 

Conveniently enough, FCC specifically says that all letter are going to be uppercase, so that’s something else to worry about (today).

Onto the actual function, I’m going to write a function that given a single character returns it’s shifted value:

function getShifted(letter) {
  var charCode = letter.charCodeAt(0) + 13;
  return String.fromCharCode(charCode);
}

 

Okay, we are now returning a shifted letter, but, we are not making sure that we never go past ‘Z’. The character code for ‘Z’ is 90, so anything over that needs to go back to ‘A’ (char. code 65) and sum up from there:

function getShifted(letter) {
  var charCode = letter.charCodeAt(0) + 13;

  if (charCode > 90) {
    charCode = 64 + (charCode - 90);
  }

  return String.fromCharCode(charCode);
}

 

That is a bit better, we now make sure that anything beyond ‘Z’ will go back to ‘A’ (we start counting at 64 to that ‘A’ itself is included). Now, I’m going to make sure that whatever we get as input, is actually a letter, and not a symbol or especial character:

function getShifted(letter) {
  if (/[A-Z]/.test(letter)) { // Test for valid uppercase characters.
    var charCode = letter.charCodeAt(0) + 13;

    if (charCode > 90) {
      charCode = 64 + (charCode - 90);
    }

    return String.fromCharCode(charCode);
  } else {
    return letter; // Non letters are returned without any alterations.
  }
}

 

As a plus, let’s also convert the letter to uppercase:

function getShifted(letter) {
  letter = letter.toUpperCase();
  if (/[A-Z]/.test(letter)) {
    var charCode = letter.charCodeAt(0) + 13;

    if (charCode > 90) {
      charCode = 64 + (charCode - 90);
    }

    return String.fromCharCode(charCode);
  } else {
    return letter;
  }
}

 

I’m also going to replace the inner if statement and use the ternary operator:

function getShifted(letter) {
  letter = letter.toUpperCase();
  if (/[A-Z]/.test(letter)) {
    var charCode = letter.charCodeAt(0) + 13;
    return String.fromCharCode(charCode > 90 ? 64 + charCode - 90 : charCode);
  } else {
    return letter;
  }
}

 

Now, let’s place this function inside our actual solution and use map to do the work for us:

function rot13(str) {

  return str.split('').map(getShifted).join('');

  function getShifted(letter) {
    letter = letter.toUpperCase();
    if (/[A-Z]/.test(letter)) {
      var charCode = letter.charCodeAt(0) + 13;
      return String.fromCharCode(charCode > 90 ? 64 + charCode - 90 : charCode);
    } else {
      return letter;
    }
  }
}

 

Oh woah, that single line does quite a lot doesn’t it. We are actually turning the string into an array, executing the getShifted function on each array element (each character) thanks to map and the joining it back into a string before returning it.

That’s it for the Caesars Cipher bonfire challenge, feel free to ask any question via email, comment or twitter!