 # Caesars Cipher

## Hints

### Hint 1

Use String.charCodeAt() to convert the English character to ASCII.

### Hint 2

Use String.fromCharCode() to convert ASCII to English character.

### Hint 3

Leave anything that doesn’t come between A-Z as it is.

## Solutions

Solution 1 (Click to Show/Hide)
``````function rot13(str) {
// Split str into a character array
return (
str
.split("")
// Iterate over each character in the array
.map.call(str, function(char) {
// Convert char to a character code
var x = char.charCodeAt(0);
// Checks if character lies between A-Z
if (x < 65 || x > 90) {
return String.fromCharCode(x); // Return un-converted character
}
//N = ASCII 78, if the character code is less than 78, shift forward 13 places
else if (x < 78) {
return String.fromCharCode(x + 13);
}
// Otherwise shift the character 13 places backward
return String.fromCharCode(x - 13);
})
.join("")
); // Rejoin the array into a string
}
``````

#### Code Explanation

• A string variable `nstr` is declared and initialized to store the decoded string.
• The for loop is used to loop through each character of the input string.
• If the character is not uppercase English alphabets(i.e. its ascii doesn’t lie between 65 and 91 ), we’ll leave it as it is and continue with next iteration.
• If it’s the uppercase English alphabet, we’ll subtract 13 from its ascii code.
• If the ascii code is less than 78, it’ll get out of range when subtracted by 13 so we’ll add 26 (number of letters in English alphabets) to it so that after A it’ll go back to Z. e.g. M(77) <==> 77-13 = 64(Not an English alphabet) +26 = 90 <==> Z(90).

Solution 2 (Click to Show/Hide)
``````// Solution with Regular expression and Array of ASCII character codes
function rot13(str) {
var rotCharArray = [];
var regEx = /[A-Z]/;
str = str.split("");
for (var x in str) {
if (regEx.test(str[x])) {
// A more general approach
// possible because of modular arithmetic
// and cyclic nature of rot13 transform
rotCharArray.push(((str[x].charCodeAt() - 65 + 13) % 26) + 65);
} else {
rotCharArray.push(str[x].charCodeAt());
}
}
str = String.fromCharCode.apply(String, rotCharArray);
return str;
}

// Change the inputs below to test
rot13("LBH QVQ VG!");
``````

#### Code Explanation

• An empty array is created in a variable called `rotCharArray` to store the character codes.
• The `regEx` variable stores a regular expression for all uppercase letters from A to Z.
• We split `str` into a character array and then use a for loop to loop through each character in the array.
• Using an if statement, we test to see if the string only contains uppercase letters from A to Z.
• If it returns true, we use the `charCodeAt()` function and rot13 transformation to return the correct value, otherwise we return the initial value.
• We then return the string with the character codes from the `rotCharArray` variable.

Algorithm Explanation:

``````    ALPHA	KEY	BASE 	 	 	 ROTATED	ROT13
-------------------------------------------------------------
[A]     65  <=>   0 + 13  =>  13 % 26  <=>  13 + 65 = 78 [N]
[B]     66  <=>   1 + 13  =>  14 % 26  <=>  14 + 65 = 79 [O]
[C]     67  <=>   2 + 13  =>  15 % 26  <=>  15 + 65 = 80 [P]
[D]     68  <=>   3 + 13  =>  16 % 26  <=>  16 + 65 = 81 [Q]
[E]     69  <=>   4 + 13  =>  17 % 26  <=>  17 + 65 = 82 [R]
[F]     70  <=>   5 + 13  =>  18 % 26  <=>  18 + 65 = 83 [S]
[G]     71  <=>   6 + 13  =>  19 % 26  <=>  19 + 65 = 84 [T]
[H]     72  <=>   7 + 13  =>  20 % 26  <=>  20 + 65 = 85 [U]
[I]     73  <=>   8 + 13  =>  21 % 26  <=>  21 + 65 = 86 [V]
[J]     74  <=>   9 + 13  =>  22 % 26  <=>  22 + 65 = 87 [W]
[K]     75  <=>  10 + 13  =>  23 % 26  <=>  23 + 65 = 88 [X]
[L]     76  <=>  11 + 13  =>  24 % 26  <=>  24 + 65 = 89 [Y]
[M]     77  <=>  12 + 13  =>  25 % 26  <=>  25 + 65 = 90 [Z]
[N]     78  <=>  13 + 13  =>  26 % 26  <=>   0 + 65 = 65 [A]
[O]     79  <=>  14 + 13  =>  27 % 26  <=>   1 + 65 = 66 [B]
[P]     80  <=>  15 + 13  =>  28 % 26  <=>   2 + 65 = 67 [C]
[Q]     81  <=>  16 + 13  =>  29 % 26  <=>   3 + 65 = 68 [D]
[R]     82  <=>  17 + 13  =>  30 % 26  <=>   4 + 65 = 69 [E]
[S]     83  <=>  18 + 13  =>  31 % 26  <=>   5 + 65 = 70 [F]
[T]     84  <=>  19 + 13  =>  32 % 26  <=>   6 + 65 = 71 [G]
[U]     85  <=>  20 + 13  =>  33 % 26  <=>   7 + 65 = 72 [H]
[V]     86  <=>  21 + 13  =>  34 % 26  <=>   8 + 65 = 73 [I]
[W]     87  <=>  22 + 13  =>  35 % 26  <=>   9 + 65 = 74 [J]
[X]     88  <=>  23 + 13  =>  36 % 26  <=>  10 + 65 = 75 [K]
[Y]     89  <=>  24 + 13  =>  37 % 26  <=>  11 + 65 = 76 [L]
[Z]     90  <=>  25 + 13  =>  38 % 26  <=>  12 + 65 = 77 [M]
``````

Solution 3 (Click to Show/Hide)
``````function rot13(str) {
// LBH QVQ VG!
return str.replace(/[A-Z]/g, L =>
String.fromCharCode((L.charCodeAt(0) % 26) + 65)
);
}
``````

#### Code Explanation

Understanding modulo operator (sometimes called modulus operator) symbolically represented as `%` in JavaScript is key to understanding the algorithm.
This is an interesting operator which shows up in various places of Engineering e.g. in cryptography.

Basically, operated on a number, it divides the number by the given divisor and gives the remainder of the division.
For Example,

• `0 % 5 = 0` because `0 / 5 = 0` and the remainder is `0`.

• `2 % 5 = 2` because `2 / 5 = 0` and the remainder is `2`

• `4 % 5 = 4` because `4 / 5 = 0` and the remainder is `4`

• `5 % 5 = 0` because `5 / 5 = 1` and the remainder is `0`

• `7 % 5 = 2` because `7 / 5 = 1` and the remainder is `2`

• `9 % 5 = 4` because `9 / 5 = 1` and the remainder is `4`

• `10 % 5 = 0` because `10 / 5 = 2` and the remainder is `0`

But you must have noticed a pattern here.
As you might have noticed, the amazing modulo operator wraps over the LHS value when it just reaches multiples of the RHS value.
e.g. in our case, when `LHS = 5`, it wrapped over to `0`
OR
when `LHS = 10`, it wrapped over to `0` again.

Hence, we see the following pattern emerging

``````     0 ⇔ 0
1 ⇔ 1
2 ⇔ 2
3 ⇔ 3
4 ⇔ 4
5 ⇔ 0
6 ⇔ 1
7 ⇔ 2
8 ⇔ 3
9 ⇔ 4
10 ⇔ 0
``````

Hence, we conclude that using modulo operator, one can map a range of values to a range between [`0` to `DIVISOR - 1`]. In our case, we mapped [`5 - 9`] between [`0 - 4`] or mapped [`6 - 10`] between [`0 - 4`].

Did you understand till this?

Now let us consider mapping a range of `26` numbers i.e. between [`65 - 90`] which represents uppercase [English alphabets] in Unicode character set to a range of numbers between [`0 - 25`].

``````    [A]  65 % 26 ⇔ 13
[B]  66 % 26 ⇔ 14
[C]  67 % 26 ⇔ 15
[D]  68 % 26 ⇔ 16
[E]  69 % 26 ⇔ 17
[F]  70 % 26 ⇔ 18
[G]  71 % 26 ⇔ 19
[H]  72 % 26 ⇔ 20
[I]  73 % 26 ⇔ 21
[J]  74 % 26 ⇔ 22
[K]  75 % 26 ⇔ 23
[L]  76 % 26 ⇔ 24
[M]  77 % 26 ⇔ 25
[N]  78 % 26 ⇔  0
[O]  79 % 26 ⇔  1
[P]  80 % 26 ⇔  2
[Q]  81 % 26 ⇔  3
[R]  82 % 26 ⇔  4
[S]  83 % 26 ⇔  5
[T]  84 % 26 ⇔  6
[U]  85 % 26 ⇔  7
[V]  86 % 26 ⇔  8
[W]  87 % 26 ⇔  9
[X]  88 % 26 ⇔ 10
[Y]  89 % 26 ⇔ 11
[Z]  90 % 26 ⇔ 12
``````

As you can notice, each number in the range of [`65 - 90`] maps to a unique number between [`0 - 25`].
You might have also noticed that each given number (e.g. `65`) maps to another number (e.g. `13`) which can be used as an offset value (i.e. `65 + OFFSET`) to get the ROT13 of the given number.

E.g. `65` maps to `13` which can be taken as an offset value and added to `65` to give `78`.

``````    [A]  65 % 26 ⇔ 13 + 65 =  78 [N]
[B]  66 % 26 ⇔ 14 + 65 =  79 [O]
[C]  67 % 26 ⇔ 15 + 65 =  80 [P]
[D]  68 % 26 ⇔ 16 + 65 =  81 [Q]
[E]  69 % 26 ⇔ 17 + 65 =  82 [R]
[F]  70 % 26 ⇔ 18 + 65 =  83 [S]
[G]  71 % 26 ⇔ 19 + 65 =  84 [T]
[H]  72 % 26 ⇔ 20 + 65 =  85 [U]
[I]  73 % 26 ⇔ 21 + 65 =  86 [V]
[J]  74 % 26 ⇔ 22 + 65 =  87 [W]
[K]  75 % 26 ⇔ 23 + 65 =  88 [X]
[L]  76 % 26 ⇔ 24 + 65 =  89 [Y]
[M]  77 % 26 ⇔ 25 + 65 =  90 [Z]
[N]  78 % 26 ⇔  0 + 65 =  65 [A]
[O]  79 % 26 ⇔  1 + 65 =  66 [B]
[P]  80 % 26 ⇔  2 + 65 =  67 [C]
[Q]  81 % 26 ⇔  3 + 65 =  68 [D]
[R]  82 % 26 ⇔  4 + 65 =  69 [E]
[S]  83 % 26 ⇔  5 + 65 =  70 [F]
[T]  84 % 26 ⇔  6 + 65 =  71 [G]
[U]  85 % 26 ⇔  7 + 65 =  72 [H]
[V]  86 % 26 ⇔  8 + 65 =  73 [I]
[W]  87 % 26 ⇔  9 + 65 =  74 [J]
[X]  88 % 26 ⇔ 10 + 65 =  75 [K]
[Y]  89 % 26 ⇔ 11 + 65 =  76 [L]
[Z]  90 % 26 ⇔ 12 + 65 =  77 [M]
``````

#### Code Explanation

• `String.prototype.replace` function lets you transform a `String` based on some pattern match (defined by a regular expression), and the transformation function (which is applied to each of the pattern matches).
• Arrow function syntax is used to write the function parameter to `replace()`.
• `L` represents a single unit, from every pattern match with `/[A-Z]/g` - which is every uppercase letter in the alphabet, from `A` to `Z`, present in the string.
• The arrow function applies the `rot13` transform on every uppercase letter from English alphabet present in the given string.

Solution 4 (Click to Show/Hide)
``````function rot13(str) {
const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
return str
.split('')
.map(char => {
const pos = alphabet.indexOf(char);
return pos >= 0 ? alphabet[(pos + 13) % 26] : char;
})
.join('');
}
``````
Solution 5 (Click to Show/Hide)
``````function rot13(str) {
str.toUpperCase(); // Convert `str` string to uppercase letters
var abc = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M"];
var nop = ["N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];
var arr = str.split(""); // Splits `str` into an array where each element is an individual character (including non-alphabetic characters)

for (var i = 0; i < arr.length; i++) { // Iterate number of `arr` elements
for (var j = 0; j < abc.length; j++) { // Iterate number of `abc`/`nop` array elements
if (arr[i] === abc[j]) {
arr[i] = nop[j]; // Swap the `arr` character for the corresponding `nop` array character
} else if (arr[i] === nop[j]) {
arr[i] = abc[j]; // Swap the `arr` character for the corresponding `abc` array character
}
}
}

return arr.join(""); // Join all `arr` array characters back into a string, returning the deciphered `str` with all non-alphabetical characters preserved
}

rot13("FHCRE FRPERG!!!");
``````

Code Explanation

• The string is split into an array of characters
• Each alphabetical character is replaced with its shifted counterpart
• The final result is `join`ed into a string and returned

Note: This approach works for a shift of 13 characters. A different approach will be required for a different sized shift.

33 Likes

hi buddy i’m confused about “when do you use call in the map function”. can you please explain?

2 Likes

The call() method calls a function with a given this value and arguments provided individually.

MDN

Personally I think it can be done without it.

1 Like

The Basic Code Solution no longer matches the basic Code Explanation.

23 Likes

yes it can @Rafase282

2 Likes

The advanced solution is very nice.

9 Likes

Hi coders, I did ROT13 in a bit different way than others posted solutions here. Just wanna share with you guys to see if it is a good solution or not and plus how could I improve it. Thanks

``````
function rot13(str) { // LBH QVQ VG!
var newStr = "";

for ( var i = 0; i < str.length; i++ ) {

char = str.charCodeAt(i);

if ( char < 65 || char > 90 ) {
char = char;
}
else {
char += 13;

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

newStr += String.fromCharCode(char);
}

return newStr;
}``````
36 Likes

Hey, I like your code. Mine looks actually quite similar but maybe a smidgen cleaner and more readable. Check it out: (Sorry couldn’t figure out how to style it properly on the fly so I just cut it out… Is there a template or something? ;))

28 Likes

yeah its a bit nicer, keep coding. 2 Likes

This was my answer, any pointers or feedback greatly appreciated as i’m sure it could be optimised/tidied. Thanks!

``````function rot13(str) { // LBH QVQ VG!
// Create new empty array
var newWord = [];
// create for loop for length of str
for (i = 0; i < str.length; i++) {
// put charcode at i in to it's own variable
var newLet = str.charCodeAt(i);
// if charcode is between A-Za-z
if (newLet >= 65 && newLet <= 90) {
// take away 13 from the charcode
newLet -= 13;
// if charcode is now below A-Z (in the numbers)
if (newLet < 65) {
// add 26 to get to A-Z equivalent
newLet += 26;
}
}
// push the new charcode, converted to the actual character, in to an array
newWord.push(String.fromCharCode(newLet));
}
// join the array back together and return the answer
return newWord.join('');
}``````
2 Likes

This was my attempt 12 Likes

Thank you. I also followed a similar path; and IMHO our way looks much prettier than others . The place I was stuck (and the reason why I came to this wiki) was how to solve the rotation within A - Z range. Didn’t think of using the center location (letter N-78) and moving forward/backward.
Very nice. This was fun.

2 Likes  1 Like

I did the same solution too 1 Like
``````function rot13(str) { // LBH QVQ VG!
var arr = str.split("");
var newVal=0;

return arr.map(function(val){

if (val !== " " && val.charCodeAt() >= 65 && val.charCodeAt() <= 90){

newVal= val.charCodeAt() + 13;

if ( newVal  > 90){
newVal-= 26;
}

newVal = String.fromCharCode(newVal);

return newVal;

}
else{
return val;
}

}).join("");

}
``````

This is a solution I made without using a for loop.

4 Likes

Here’s what I did:

``````function rot13(str){
return str.split('').map(function(val){
var c = val.charCodeAt(0) - 65;
if (c >= 0 && c <= 25)
return String.fromCharCode( ((c + 13) % 26) + 65 );
else
return val;
}).join('');
}
``````
1. Split the string to get individual characters.
2. Shift character values to a range between 0 and 25 (26 characters) by subtracting 65. If a character is not in the range, skip and return the array value;
Ex: `66` is the code for letter `B`. If we do `66 - 65` we get `1`, so that A is in position 0, B in 1, C in 2 etc.
3. Add 13 (our rot value) to the value.
4. Get the modulo 26 of the operation. If the number is less than 26, we get the same number. If it’s larger than 26, we get the remainder.
Ex: `13 % 26 = 13` and `42 % 26 = 16`.
5. Return the result and shift back to the actual letter codes.
6. Join back return;
3 Likes

Please what is wrong with my code?
function rot13(str) { // LBH QVQ VG!
var b =[];
var c =[]; var res =[];

for(i=0; i < str.length; i++){
b.push(str.charCodeAt(i));
}

for(j=0; j < b.length; j++){
if(b[j] >= 65 && b[j] <=77 ){
c.push(b[j]+13);
}else if( b[j]>=78 && b[j] <=90){
c.push(b[j]-13);
} else if (b[j] === 32 || b[j] === (’!’,’?’,’.’) ){
c.push(b[j]);
}
} for(v = 0; v < c.length; v++){ res.push(String.fromCharCode(c[v]));}
return res.join(’’);
}

// Change the inputs below to test
rot13(“SERR PBQR PNZC”);

1 Like

Changed to this:
function rot13(str) { // LBH QVQ VG!
var newWord = [];

for(i=0; i < str.length; i++){
var newLet = str.charCodeAt(i);

if(newLet >= 65 && newLet <=77 ){
newLet += 13;
}else if( newLet >=78 && newLet <=90){
newLet -= 13;
}else if (newLet === 32 || newLet === (’!’,’?’,’.’)){

newLet = newLet;
}

``````newWord.push(String.fromCharCode(newLet));
``````

}

return newWord.join(’’);
}

Why this one works? What about “!”,"?" and “.” ?

2 Likes