# Caesars Cipher - other approaches?

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!");
``````

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 1 Like

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!");
``````
3 Likes

Thanks for the link - yep, that formula would have taken me quite a while to work out… Nice! Like that miles better. Thanks.

1 Like

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));
});
}
``````
13 Likes

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

1 Like

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");
``````
2 Likes

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 ``````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;

}``````

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.

Thanks so much!! I didn’t know it can be done that way, so much learning to do Gonna go clean up my code now!

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!

3 Likes

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;
}
``````

Well, it took a long time to write this code without any hints. It may look quite dirty, but works perfectly. ``````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.");``````

Here is mine in repl.it

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!");

``````

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.

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~

what is the test method ?

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");
``````
1 Like