Writing A Caesar Shift Cipher Function with JavaScript: Part 1
Tags: javascript, programming, ciphers, puzzles
Published: 2021-11-25 18:35:23

A [Caesar cipher](https://en.wikipedia.org/wiki/Caesar_cipher) is an encryption technique. You take each letter in a word, and shift it forward by a certain number of alphabetical degrees to obscure its meaning. Thus, 'cab' with a degree shift of 1 become 'dbc'. The person you send the cipher to knows the number and shift degree to decode it back to its original meaning. 

I wanted to write a function that would take in two parameters, `shiftDegrees` and `inputText`, and return a string that shifted each letter forward by the specified degree.

So I started out with:

```
function caesarShift(inputText, shiftDegrees) { 

}
```
I also needed an alphabet to refer this function to, so I pulled in an array:

```
const lowerCaseAlphabet = [
    'a',
    'b',
    'c',
    'd',
    'e',
    'f',
    'g',
    'h',
    'i',
    'j',
    'k',
    'l',
    'm',
    'n',
    'o',
    'p',
    'q',
    'r',
    's',
    't',
    'u',
    'v',
    'w',
    'x',
    'y',
    'z',
]
```

Now to attend to the edge-cases! If I'm honest, these occurred to me towards the end of writing the function, but I put them at the top of my logic so I'm explaining them now. Inside the function I have:

```
    if (shiftDegrees > 26 || shiftDegrees < -26) {
        return 'use a shift between -26 and 26'
    }
```
Another solution would be take 26 as a factor of any numbers greater than it and then take the remainder as the `shiftDegree`. It's a stretch goal for me, but you're welcome to add your solution in the comments.

The other edge cases were invalid params:

```
    if (typeof shiftDegrees != 'number') {
        return 'shiftDegree must be a number'
    }
    if (typeof inputText != 'string') {
        return 'inputText must be string'
    }
```

Then it was time to eliminate capitalization issues:

```
const inputTextToLowerCase = inputText.toLowerCase()
```

I'm also going to want to capture the indexes of each letter in the `inputString`, so I set this variable to an empty array:

```
let arrayOfAlphaIdxes = []
```

Now, to isolate the indexes of each letter in my input word, I ran a couple for loops:

```
    for (let i = 0; i < inputText.length; i++) {
        for (let j = 0; j < lowerCaseAlphabet.length; j++) {
            if (inputTextToLowerCase[i] === lowerCaseAlphabet[j]) {
                arrayOfAlphaIdxes.push(j)
            }
        }
    }
```
Basically what this does is run through the length of the `inputText` string, and match each value of each letter to an index in the alphabet. Then I pushed that new value to an array, `arrayOfAlphaIdxes`.

Now, I needed to move those indexes. I did another for loop and added `shiftDegrees` to each one and pushed it to `arrayOfMovedAlphaIdxes`, so `arrayOfMovedAlphaIdxes` represented the Caesar-shifted indexes. 

The last thing to do is take the values of the letters at each of the new indexes and translate them into a new string:

```
 // for loop that creates an array of new letters with the new shifted indexes
    arrayWithNewLetters = []
    for (let i = 0; i < arrayOfMovedAlphaIdxes.length; i++) {
        for (let j = 0; j < lowerCaseAlphabet.length; j++) {
            if (arrayOfMovedAlphaIdxes[i] === j) {
                arrayWithNewLetters.push(lowerCaseAlphabet[j])
            }
        }
    }
```
I did this by creating an empty array, and pushing the new values to it with a double for loop to capture the values from the array of indexes and from the alphabet. 

The last piece of the puzzle was to create a string to return:

```
    const stringWithCommas = arrayWithNewLetters.toString()

    const removedCommas = stringWithCommas.split(',').join('')

    return removedCommas
```

At this point, this function:

```
caesarShift('HELLO', 2)
```

had this output:

```
jgnnq
```

This _looks_ like the function is outputting what we want, but let's try a higher shift degree: 

```
caesarShift('HELLO', 20)
```

outputs:

```
y
```

The response is truncated! I forgot to add logic to make the index count 'wrap around', so to speak, the alphabet array. What to do now? Well, let's get to know our unknowns. The first unknown is the distance from the end. Because the distance of the array is fixed, I found that by doing this:
```
 let distanceFromEndIncludingCurrentLetter = 27 - arrayOfAlphaIdxes[i]
```
Now we know that _if_ `shiftDegrees` is greater than the distance from the end, _then_ we'll need to do some triage. 

How to fix the issue? Well, we do know that the difference between `shiftDegrees` and the distance to the end is the number of indexes we'll need to shift the value from the beginning in order to 'loop' the array. So we'll assign the new index by that delta, `shiftDegrees - distanceFromEndIncludingCurrentLetter`.

In the end I changed my function to:

```
    //for loop that changes the arrayindex by shift number
    for (let i = 0; i < arrayOfAlphaIdxes.length; i++) {
        let distanceFromEndIncludingCurrentLetter = 27 - arrayOfAlphaIdxes[i]
        if (shiftDegrees < distanceFromEndIncludingCurrentLetter) {
            let newIdx = arrayOfAlphaIdxes[i] + shiftDegrees
            arrayOfMovedAlphaIdxes.push(newIdx)
        } else {
            let differenceBtw =
                shiftDegrees - distanceFromEndIncludingCurrentLetter
            arrayOfMovedAlphaIdxes.push(differenceBtw)
        }
    }
```

The full code is on my [Github profile](https://github.com/Cerchie/caesar-cipher/blob/main/README.md) if you're interested! I'd love to hear feedback. ❤️