A long time ago, some dude needed to send a letter to his lover but didn’t want the messenger to be reading it. After all, messengers were notorious gossips and if this particular messager knew what was in the letter then the whole of the city would have known by tea time.
He couldn’t very well deliver it himself, after all, he was an important man and he absolutely could not let the young lady think he was smitten now could he? After considering if he should break off the relationship, he had a brilliant idea that allowed him to still use the gossipy messenger but keep his super-secret woo juice secret.
Since people were not too bright back in the day, he thought that if he switched the characters in the letter, no one would figure out what the letters said except for his paramour who knew which letters represented which. And so the simple substitution cipher was born.
Ok ok ok. I made that whole thing up. That’s not how ciphers were invented. Anyway, moving on to today’s problem.
ROT13 Cipher Problem
Today we are tasked with creating a special variant of the Caesar cipher called ROT13. Basically, each letter of the alphabet is shifted by 13 places such that a becomes n, b becomes o, etc.
There are a few ways of doing this. The two that came to mind first would be the mathematical way and the dictionary way.
The mathematical way is basically that for each letter in the given string you add 13 to the character code. If it’s less than or equal to the end letter’s character code then that’s the encrypted value. On the other hand, if it is greater than the end letter character code then you add the difference to the starting letter’s char code.
This can be written in one or two lines but we are not going to do it that way. While less code is great I always prefer readability over one-liners especially if the one-liners require some effort to understand. So let’s do the more readable way.
Solution
Here, we create a dictionary that maps each letter to its encrypted value. Then simply map the input string letter by letter. No mathematics is required.
const rot13 = (str) => {
const input = 'abcdefghijklmnopqrstuvwxyz'.split('')
const output = [...input.slice(13), ...input.slice(0, 13)]
const cypher = input.reduce((cypher, letter, index) => {
cypher[letter] = output[index]
cypher[letter.toUpperCase()] = output[index].toUpperCase()
return cypher
}, {})
const encryptedStr = str.split('').map(char => {
return cypher[char] || char
}).join('')
return encryptedStr
}
Code language: JavaScript (javascript)
If you look at the code you’ll realize that lines 2 through 8 are just setting up the dictionary. If all we wanted was just that map couldn’t we literally hard code the dict?
const cypher = {
a: n,
b: o,
...
}
Code language: JavaScript (javascript)
Yes, but
- That would be boring
- That would make it damn near impossible to extend in the future. For example, if we wanted to rotate by 6 or 17.
Is this solution longer? Yes. But a junior developer will have less trouble understanding it. Code doesn’t have to be complicated. Anyway, I’d love to see what you come up with if you attempt this challenge. Hit me up on Twitter @phoexer and as always happy coding.