Caesars Cipher, Works but I wanted to to it better! (Spoilers)

This code works and I’ve tried to explain my thinking, but I really wanted to use a regular expression to match all the Capital letters, but I struggled to get it to work.

function rot13(str) { // LBH QVQ VG!

var code = []; // create an empty array to hold the code numbers
var newString = []; // create an empty array to hold the decoded string
//iterate through the string and push its
//charCode to the code array
for (var i = 0; i < str.length; i++) {
    code.push(str.charCodeAt([i]));
}
//console.log(code);
// function to map each value of code to a new array
// codeRot13, adding 13 to each number
var codeRot13 = code.map(function (val) {
    return val + 13;
});
//console.log(codeRot13);
//Iterate though codeRote13 and if the value is above 90(z) return
// to 65(a) and add the balance
//else if that results in going over 78 (A+13) remove the 13.
for (var j = 0; j < codeRot13.length; j++) {
    if (codeRot13[j] > 90) {
        codeRot13[j] = 65 + (codeRot13[j] - 91);
    } else if (codeRot13[j] < 78) {
        codeRot13[j] = codeRot13[j] - 13;
    }
}
//console.log(codeRot13);
//Turn it back to a string
for (var k = 0; k < codeRot13.length; k++) {
    newString.push(String.fromCharCode(codeRot13[k]));
}
newString = newString.join('');
//console.log(newString);
return newString;

}

Any help on how I could do this and still understand what going on would be appreciated. Thanks

Here is my attempt:

function rot13(str) {
  var result = [];
  
  str.split('').forEach(function(i) {
    if (/[A-Z]/.test(i)) {
      i = (String.fromCharCode(65 + (i.charCodeAt(0) - 65 + 13) % 26));
    } 
      result.push(i);
  });
  
  return result.join('');
}

I split string to get an array and then loop through that array and test each element (character).

If it is a capital letter do the conversion by getting that letters position in alphabet, adding 13 (ROT number) and applying modulus of 26 (number of letters in alphabet) so if the number is bigger than 26 it loops back to the beginning.

Push i to the result array;

Join result array together to get string and return resulting string.


Or you can write it in one line using map() and ES6 (not very readable, but looks cool):

function rot13(str) {
  return str.split('').map(i => i = /[A-Z]/.test(i) ? (String.fromCharCode(65 + (i.charCodeAt(0) - 65 + 13) % 26)) : i).join('');
}
1 Like

Wow, both your examples are so fantastic, admittedly I find the first one easier to follow, but I agree the second example is so cool.

Thank you for taking the time to show me your code, I still have a lot to learn, but seeing great code really helps :slight_smile:

I come from a more PHP back ground and this was my shot at this, quite simple although i liked Jenovs own pretty neat.

function rot13(str) {
  
  // Ensure string is upper case as upper case and lower case have different unicode value
  str.toUpperCase();
  
  var newStr = '';
  var letter;
  
  for ( var i = 0; i < str.length; i++ ) {
    
    // Get unicode value before decripted
    var result = str.charCodeAt(i);
    
    if ( result <= 77 && result >= 65 ) {
      
      // Get Decripted letter
      letter = String.fromCharCode(result + 13);
      
    } else if ( result > 77 && result <= 90 ) {
      
      // Get decripted letter
      letter = String.fromCharCode(result - 13);
      
    } else {
      
      letter = String.fromCharCode(result);
      
    }
    
    newStr = newStr + letter;
  
  }
  
  return newStr;
  
}

Thanks, That’s a neat bit of code and very easy to understand.

Here is my solution:

function rot13(str) { // LBH QVQ VG!
var arr = [];
for (var i = 0; i < str.length; i++) {
var num = str.charCodeAt(i);
arr.push(num);
}

for (var j = 0; j < arr.length; j++) {
if ( arr[j] >= 65 && arr[j] <= 77 ) {
arr[j] = arr[j] + 13;
}
else if (arr[j] >= 78 && arr[j] <= 90) {
arr[j] = arr[j] - 13;
}
}
var answer = β€œβ€;
for (var k = 0; k < arr.length; k++) {
var decode = String.fromCharCode(arr[k]);
answer += decode;
}

return answer;

}

Yeah, I know what you are talk about. Personally, I try to use all the JS functions as much as possible.

Here is my solution. I use repl.it to have a working example of the algorithm.

/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SOLUTION CODE
https://repl.it/E1dg/3
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
function rot13(str) { // LBH QVQ VG!
    // Split str into a character array
    return str.split('')
        // Iterate over each character in the array
        // c = current element
        // i = current index
        .map(function(c, i) {
            // Convert char to a character code
            var strCode = str.charCodeAt(i);
            // Checks if character lies between A - M
            if (strCode >= 65 && strCode <= 77) {
                return String.fromCharCode((strCode) + 13);
                // Checks if character lies betweenm N - Z
            } else if (strCode >= 78 && strCode <= 90) {
                return String.fromCharCode((strCode) - 13);
                // Return character
            } else {
                return c;
            }
            //console.log("i: " + i + " : " + c + " : " + strCode + " : " + strChange);
        }).join(''); // Rejoin the array into a string
}

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

This is what I tried…

function rot13(str) {
  var num = 0;
  var myString = "";
  for (var i = 0; i < str.length; i++) {
    num = str.charCodeAt(i);
    if (num >= 65) {
      num += 13;
    }
    if (num > 90) {
      num -= 26;
    }
    myString += String.fromCharCode(num);
  }
  return myString;
}
1 Like

This took me a while:

function rot13(str) { // LBH QVQ VG!

  var strArray = str.split("");
 strArray = strArray.map(function(letter){  
 return letter.charCodeAt();
   
});

  strArray = strArray.map(function(code1){
    if (code1 >= 65+13 && code1 <= 90) {
      code1 -=13;
    } 
   else if (code1 < 65+13 && code1 >= 65) {
     code1 += 13;
   } 
    return String.fromCharCode(code1);
  });
  return strArray.join("");

}

After finally getting this algo working with some hard-coded exceptions for the punctuation, that ES6 solution is blowing my brain apart. SO COOL.

Here’s my solution using a slightly different method

function rot13(str) {
  return str.replace(/[A-Z]/ig, c => ( 
    String.fromCharCode(c.charCodeAt() + (/[A-M]/.test(c) ? 13 : -13))
  ));
}
4 Likes

function rot13(str) { // LBH QVQ VG!

var n ,val;
var ch =0 ;

var decodede_str=’’;
var encry_str =str ;
// encry_str = str.split(’’);
var len = encry_str.length;

for(var i=0 ; i< len ;i++ ){

n = encry_str.charCodeAt(i);

if(n < 78 && n>=65){
ch = n+13;}
else
if( n >=78 && n<91)
ch = n-13;
else
if(n>91){
ch = 65 + (n-91);}
else{
ch = n;
}

val = String.fromCharCode(ch);
decodede_str = decodede_str + val;
console.log(decodede_str);
}
return decodede_str;

}
// Change the inputs below to test
rot13(β€œGUR DHVPX OEBJA QBT WHZCRQ BIRE GUR YNML SBK.”);

Here’s my solution


function rot13(str) { // LBH QVQ VG!
  
  function decode(val){
    // check if character is between A-Z
    if (val>='A' && val<='Z') {
      return val.charCodeAt() > (64+13) ? String.fromCharCode(val.charCodeAt()-13) : String.fromCharCode(val.charCodeAt()+13); 
    } else {
      // not A-Z; so return original character
      return val;
    }
  }
  
  return str.split('').map( decode ).join('');

}

// Change the inputs below to test
rot13("GUR DHVPX OEBJA QBT WHZCRQ BIRE GUR YNML SBK.")

I think, this is the simplest solution. I understand others have developed some really cool/advanced ones, but this is so easy to understand. Great job :slight_smile:

What is test(c) ?

whew I finally made it through the basic algos. Here is what I came up with for this last one
I like my version because 1) you can clearly see the relationship between input and output and 2) it is easy to swap out the cipher array for another (such as [β€˜t’, β€˜h’, β€˜e’, β€˜q’, β€˜u’, β€˜i’ ,β€˜c’ ,β€˜k’, β€˜b’, 'r ', β€˜o’, β€˜w’ ,β€˜n’, β€˜f’, β€˜o’ , β€˜x’…]
function rot13(str) {
var abc = [β€˜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’ ];
var nop = [ β€˜N’, β€˜O’, β€˜P’, β€˜Q’, β€˜R’, β€˜S’, β€˜T’, β€˜U’, β€˜V’, β€˜W’, β€˜X’, β€˜Y’, β€˜Z’, β€˜A’, β€˜B’, β€˜C’, β€˜D’, β€˜E’, β€˜F’, β€˜G’, β€˜H’, β€˜I’, β€˜J’, β€˜K’, β€˜L’, β€˜M’];
var newStr = β€œβ€;

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

if (abc.indexOf(str[i]) < 0) { // leaves symbols in
  newStr += str[i];
} else {

  newStr += nop[abc.indexOf(str[i])];
}

}
return newStr;
}

.test() is a method on the RegExp object that checks if a value passes the regex test and returns a boolean. /[A-M]/ is a regex literal, so this is checking that the character, c, in the arrow function is between the letters A-M.