Caesars Cipher - other approaches?

Caesars Cipher - other approaches?
0.0 0

#1

Wasn’t crazy about the amount of hard coding I did in my solution - did anyone have a different approach? Using a regex maybe?

    function rot13(str) { // LBH QVQ VG!
      
      var myCipher = [];
      var myArray = []; 
      
      for (i=0; i < str.length; i++) {
        // convert character - or don't if it's a punctuation mark.  Ignore spaces.
        if (str.charCodeAt(i) > 64 && str.charCodeAt(i) < 78) {
             myArray.push(String.fromCharCode(str.charCodeAt(i) + 13));
         } else if (str.charCodeAt(i) > 77 && str.charCodeAt(i) < 91) { 
             myArray.push(String.fromCharCode(77 - (90 - str.charCodeAt(i))));
         } else if (str.charCodeAt(i) > 32 && str.charCodeAt(i) < 65) {
             myArray.push(str.charAt(i));
         }
       
        // push word onto array when encountering a space or reaching the end of the string
        
        if (str.charCodeAt(i) == 32) {
          myCipher.push(myArray.join(''));
          myArray.length = 0;      
        }
        
        if (i == (str.length - 1)) {
           myCipher.push(myArray.join(''));
        }

      }

      return myCipher.join(" ");
      
    }

    // Change the inputs below to test
    rot13("SERR CVMMN!");

#2

Check out this video. It’s actually about implementing caesar’s in C, and the conditions are a bit different iirc, but the most juicy part is a mathematical formula they give you somewhere towards the end :wink:


#3

It’s unlikely that char codes are likely to change, so I would have been fine using them. I chose to just get the codes for A, Z, and N. In cases where you know absolutely that the value won’t change (for example, the freezing temperature of water will always be 0C/32F) then it’s fine to rely on that but the best practice is still to assign it to a variable. When we know a variable won’t actually vary in value we call it a “constant” and these are usually named using all capital letters (var FREEZING_C = 0;) and put them at the top of the file.

Anyway, if you want to look at a different approach, here is mine:

function rot13(str) { // LBH QVQ VG!
  var strArr = str.split('');
  var start = 'A'.charCodeAt(0);
  var middle = start + 13;
  var end = 'Z'.charCodeAt(0);
  
  strArr = strArr.map(function(currLetter){
    var code = currLetter.charCodeAt(0);
    var shift = 13;
    
    if (code >= start){
      if (code < middle){ // A-M
    }
      else if (code <= end){ // N-Z
      shift = code - middle;
      code = start;
    }
      return String.fromCharCode(code + shift);
    } 
    else { // non letters
      return currLetter;
    }
  });
  
  str = strArr.join('');
  return str;
}

// Change the inputs below to test
rot13("SERR CVMMN!");

#4

Thanks for the link - yep, that formula would have taken me quite a while to work out… :slight_smile:


#5

Nice! Like that miles better. Thanks.


#6

Here’s my solution using replace:

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

#7

-13!! Dang I made that so much more difficult than I needed to. Nice, elegant solution - thanks.


#8

Just finished mine. About two hours of work. A bit messy, could be cleaned up.

My solution
function rot13(str) {
  
  // Build arr1 - array of character codes of str
  
  var arr1 = [];
  for ( var i = 0; i < str.length; i++ ) {
    arr1.push(str.charCodeAt(i));
  }
  
  // Build arr2 - array of new character codes of str (ROT13)
  
  var arr2 = [];
  for ( var j = 0; j < str.length; j++ ) {
    if ( arr1[j] >= 65 && arr1[j] <= 77 ) {
      arr2.push(arr1[j]+13);
    }
    else if ( arr1[j] >= 78 && arr1[j] <= 90 ) {
      arr2.push(arr1[j]-13);
    }
    else arr2.push(arr1[j]);
    }
  
  // Build str2 - string made from the new character codes above
  
  var str2 = "";
  for ( var k = 0; k < str.length; k++ ) {
    var x = String.fromCharCode(arr2[k]);
    str2 = str2.concat(x);
  }
  
  return str2;
}

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

#9

Hi! I’d like to share my code as well. I did this with very, very minimal help (only using the ref links in the question and searching for the formula wrap to wrap around A - Z), took around 2hrs(?) and I am really happy about it! It’s messy but it works :smiley:

function rot13(str) { // LBH QVQ VG!
  
  var splitStr = str.split('');
  var ciphCode = [];
  var cipher = '';
  
  // loop through the str array and +13 to each charCode
  for (var i = 0; i < splitStr.length; i++) {
    
    // in the ASCII table, A - Z is 65 - 90
    if (splitStr[i].charCodeAt(splitStr[i]) > 64 && splitStr[i].charCodeAt(splitStr[i]) < 91) {      
      ciphCode.push(splitStr[i].charCodeAt(splitStr[i]) + 13);
      
      // formula to wrap around A - Z
      if (ciphCode[i] > 90) {
        ciphCode[i] = ((ciphCode[i] - 65) % 26) + 65;
      }
      
    } else {
      // push the array element as usual if it is not A - Z
      ciphCode.push(splitStr[i]);
    }
    
  }
  
  // loop ciphCode back into a string using fromCharCode
  for (var j = 0; j < ciphCode.length; j++) {    
    
    if (ciphCode[j] > 64 && ciphCode[j] < 91) {
      cipher += String.fromCharCode(ciphCode[j]); 
    } else {
      cipher += ciphCode[j];
    }
    
  }
  
  return cipher;
  
}

#10

Congrats on solving the challenge without any help! I just wanted to make one comment related to your use of the charCodeAt function. You can replace all instances of the following

splitStr[i].charCodeAt(splitStr[i])

with

splitStr[i].charCodeAt()

Since you already have the current character (splitStr[i]), using charCodeAt without giving it an index assumes index 0 (zero) which is what you want anyway. This just cleans the code up a bit.


#11

Thanks so much!! I didn’t know it can be done that way, so much learning to do :sweat_smile:

Gonna go clean up my code now!


#12

Hey guys, just wanted to show my solution, I think it’s pretty simple and does the job! Hopefully some of you might find it useful.

function rot13(str) {
  var resp = [];
  var code = str.split('');
 
  for(var i=0;i<code.length;i++){
      var index = code[i].charCodeAt();
    
      if(index>77){
             resp.push(String.fromCharCode(index-13));
      }  else if(index<=77&&index>=65){
             resp.push(String.fromCharCode(index+13));
         }else if(index<65){
             resp.push(String.fromCharCode(index));
          }
  }      
        return resp.join('');
}

Cheers!


#13

Here is my code as well; definitely need to work on regex. It would have made this a whole lot simpler like the example way above ^^

function rot13(str) { // LBH QVQ VG!
  var arr = [];
  var newString = '';
  for (var i = 0; i<str.length; i++){
      var val = str.charCodeAt(i);
    if (val >= 65 && val <= 90 ){
        if (val < 78){
          val += 13;
          var hold = String.fromCharCode(val);
          newString += hold; 
          }
        else if (val >= 78) {
          val -= 13;
          var holdE = String.fromCharCode(val);
          newString += holdE;
          }
     }
    else{
      newString += str[i];
     }
  }
   return newString;
}

#14

Well, it took a long time to write this code without any hints. It may look quite dirty, but works perfectly. :heart_eyes:

function rot13(str) {
 var myStr = "";
 var charNum = 0;
  var arr = str.split(" ");

    for(j=0;j<arr.length;j++){
    var word = arr[j];
    var empcon = "";
     
        for(i=0;i<word.length;i++){         
        var new_sym ='';
        charNum = word.charCodeAt(i);

              if(charNum < 65 || charNum >90){
                new_sym = String.fromCharCode(charNum);
              }
              else if (charNum+13<=90){
              new_sym = String.fromCharCode(charNum+13);
              }else if(charNum+13>90){
              new_sym = String.fromCharCode(64 + (charNum+13-90));
              }
          
          empcon += new_sym ;
         }
     myStr += empcon + " ";
    }

return myStr.replace(/\s*$/,'');
} 

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

#15

Here is mine in repl.it


#16

Here is mine. It’s not pretty but I think it may be fairly legible to people with basic knowledge.


function rot13(str) { // LBH QVQ VG!
  
  var regEx = /[A-M]/;
  var regEx2 = /[N-Z]/;
  var holder = [];
  
   for (var i = 0; i < str.length; i++) { 
      if (regEx.test(str[i])) {           //test if str[i] is A-M
        holder[i] = str.charCodeAt(i)+13; //if true, push ASCII+13 to holder
      } else if (regEx2.test(str[i])) {   //test if str[i] is N-Z
        holder[i] = str.charCodeAt(i)-13; //if true, push ASCII-13 to holder
      } else if (!regEx.test(str[i]) && !regEx2.test(str[i])) { //test if str[i] is neither A-M nor N-Z, i.e non-alphabetic
        holder[i] = str.charCodeAt(i); //if true, push to holder as is
      }
     } return String.fromCharCode.apply(null, holder); //return holder array as string by using .apply method
  
}

// Change the inputs below to test
rot13("FREE PIZZA!");


#17

I had to take a break from this one, disappointing being right at the end of those challenges. When I came back to it though, it was really fun to work through. I used a fairly simple solution without RegEx though:

function rot13(str) { // LBH QVQ VG!
  var tst = []; var i = 0;            // tst is array of inputs, i is iteration through strings
  var arr = [];                       // arr is array to return(?), l is length of strings to find
  ////////////////////////////////////////////////////////////////////////////////////////////////
  
  tst = str.split('');              // split string into array of strings no seperator counts each
                                    // element  
  
  function change(num) {                // function to get unicode of decoded letter
    if ((num > 90) || (num < 65)) { return num; }    // leave alone if not capital letter
    else if ((num + 13) > 90) {         // subtract if adding goes beyond Z
         return num - 13;
       }
    else return num + 13;               
  }
  
  while ( i < tst.length ) {            // iterate through array of strings to find uni vals
    var word = tst[i]; var uni = [];    // word is current string, uni is temp array of unicode
    var dec = [];                       // dec is array (yes another) to decypher unicode vals
      for ( var n=0; n < word.length; n++) {
        uni.push(word.charCodeAt(n));        // get array of unicode for decyphering
      }
    for (var p= 0; p< uni.length; p++) {    // loop through cyphered unicode
      dec.push(change(uni[p]));             // using change function, find decyphered unicode values
      arr.push(String.fromCharCode(dec[p]));  // create array of letters from decyphered unicode
      }
    i++;
  }
  /*x = arr.toString(); var re = (/,/g);
  x = x.replace(re, " ");*/
  //return String.fromCharCode(91);            //testing
  
  return arr.join('');                         // join to string (remove commas with (''))
  
}

// Change the inputs below to test              A=65, Z=90
rot13("XYNGH ORENGN AVXGH!");

I also find it fun to comment the crap out of challenges I finished afterward (can ya tell?)

TL;DR - Basically I made a function to translate unicode into letters and told it to leave anything that wasn’t a capital letter alone, that way I didn’t have to worry about putting spaces and exclamations back in. I’m happy with how it turned out.


#18

Hey Campers!

I thought it’d be nice to share my solution with ya’ll. I took a simpler approach in solving this. I’m open for suggestions. Thanks!


function rot13(str) { // LBH QVQ VG!
  var alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  str = str.split('');
  var res = '';

  for (var i = 0; i < str.length; i++) {
    if (alphabet.indexOf(str[i]) !== -1) {     // if letter exists in alphabet do the following
      if (alphabet.indexOf(str[i]) < 13) {      // if letter is positioned before the first 13 characters
        res += String.fromCharCode(str[i].charCodeAt(0) + 13);  // decode letter by adding 13 more ie 'E'->'R'
      } else {
        res += String.fromCharCode(str[i].charCodeAt(0) - 13); // if not, decode letter by subtracting 13 letter ie 'S'->'F'
      }
    } else {
      res += str[i];       // if character is not part of alphabet, simply append to solution string
    }
  }
  
  return res;
} 

// Change the inputs below to test
rot13("SERR PBQR PNZC");
// console.log(rot13("LBH QVQ VG!"));

Happy Coding~


#19

what is the test method ?


#20

Another nice thing about @joesmith100’s solution: you can make it case-insensitive by just adding i flags to both the regexes:

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

rot13("serr PBQR PNZC");