Caesars Cipher solutions

Hello everyone,

I was thinking about this project and within that thinking came up with this solution. I hope it’s ok to posting it day before we will work on it. It’s done with nested for loops and arrays but I have a question about non-alphabetic characters (it’s in if conditions at the bottom of the code). Non-alphabetic characters are very much hard coded and it is done just for passing FCC, but would be really grateful if someone can suggest solution for this part, with regex or something similar. I don’t understand what FCC means by saying “Do not transform any non-alphabetic character (i.e. spaces, punctuation), but do pass them on.” What they mean by “passing” and what by “do not transform”?

I understand that this solution is also hard coded for alphabet, but it’s just my thinking as I mentioned…Looking forward for tomorrow. Anyway, would also like to hear how someone feels about this solution. Thank you in advance, great Bootcamp and amazing lecturer and guests!

function rot13(str) {
    
    var alphabet = ["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 arrString = str.split("");
    console.log(arrString);

    var arr3 = [];
    

    for (var i = 0; i < arrString.length; i++) {
        for(var j = 0; j < alphabet.length; j++) {
            if(alphabet.indexOf(alphabet[j]) <= 12) {
                if(arrString[i] == alphabet[j]) {
                    arr3.push(alphabet[j + 13]);
                    console.log(arr3);
                }
            } else {
                if(arrString[i] == alphabet[j]) {
                    arr3.push(alphabet[j - 13]);
                    console.log(arr3);
                }
            }
        }

        if(arrString[i] == " ") {
            arr3.push(" ");
        } else if (arrString[i] == "!") {
          arr3.push("!");
        } else if (arrString[i] == "?") {
          arr3.push("?");
        } else if(arrString[i] == ".") {
          arr3.push(".");
        }
    }

    str = arr3.join("");
    console.log(str);
    return str;
}


//console.log(rot13("SERR PBQR PNZC"));
rot13("SERR PBQR PNZC!");
1 Like

Hi! I can, hopefully, give a quick answer about non- alpha characters.

It just means if it is not a letter, don’t do anything to it, let it appear in the result as is.

So the spaces will still be spaces in the ciphered text. Only the letters will change by 13 indexes.

I used a regex to check if each arr[i] was a letter, then shifted it. If it wasn’t a letter, I just pushed it to the result.

1 Like

No Alpha means spaces and punctuations or numbers. The instruction is to keep them as they are and consider deciphering only the alpha characters. You can use character arrays or the best I would recommend is to use their ASCII codes- it will make it easier for non-alpha characters.
I have actually solved it using the ASCII codes. If you look into the ASCII coding you will come up with an elegant solution. using some JS string libraries.

1 Like

Here’s what I came up with. Simply used an object to avoid maths stuff. :laughing:

function rot13(str) {
  const decipher = {
    A: "N",
    B:"O",
    C:"P",
    D:"Q",
    E:"R",
    F:"S",
    G:"T",
    H:"U",
    I:"V",
    J:"W",
    K:"X",
    L:"Y",
    M:"Z",
    N:"A",
    O:"B",
    P:"C",
    Q:"D",
    R:"E",
    S:"F",
    T:"G",
    U:"H",
    V:"I",
    W:"J",
    X:"K",
    Y:"L",
    Z:"M"
  };
  let newString="";
  for (let i=0; i<str.length; i++) {
    let lookUp = str.charAt(i);
    //console.log(lookUp);
    if(/[A-Z]/.test(lookUp) == false) {
      newString += lookUp;
    } else {
      newString += decipher[lookUp];
    }
  }
  //console.log("old " + str);
  //console.log(`new: ${newString}`);
  return newString;
}

rot13("SERR PBQR PNZC");
2 Likes

Hi!

Thank you very much for your response. I guess I was too overwhelmed to think about it yesterday and needed some refreshing support. This is what I came up with thanks to your advice and other kind fellow learners, thank you all!

This if condition goes instead of those if’s at the end of my code and it covers all non-alphabetic characters.

 if((/[^A-Z]/).test(arrString[i])) {
       arr3.push(arrString[i]);
  }
1 Like

Here is my solution

function rot13(str) {

let alphabets=[‘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’,‘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’]
let ciphered=""
for(let i=0; i<str.length;i++){
if (alphabets.includes(str[i])){
let index=alphabets.indexOf(str[i])+13;
let reqLetter=alphabets[index];
ciphered+=reqLetter;
}else{
ciphered+=str[i]
}
}

return ciphered;
}

console.log(rot13(“SERR PBQR PNZC”));

1 Like

one-line code:it work: steal from “Help me understand this one-liner for rot13 - The freeCodeCamp Forum


function rot13(a,b){return++b?String.fromCharCode((a<"["?91:123)>(a=a.charCodeAt()+13)?a:a-26):a.replace(/[a-zA-Z]/g,rot13)}
1 Like

here is mine :stuck_out_tongue:

function rot13(str) {
  const ROT1 = 'NOPQRSTUVWXYZ';
  const ROT2 = 'ABCDEFGHIJKLM';
  let newStr = "";
  var pos = 0;

  for(let i = 0; i < str.length; i++){
    if(ROT1.includes(str[i])){
      pos =  ROT1.indexOf(str[i]);
      newStr += ROT2[pos];
    } else if (ROT2.includes(str[i])){
      pos =  ROT2.indexOf(str[i]);
      newStr += ROT1[pos];
    } else {
        newStr += str[i];
    }
  }

  return newStr;
}

rot13("SERR PBQR PNZC");

1 Like

using % mod operator to short my code

const alphabet = ["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"];
function rot13(str) {
  let decodedStr=""
  for(let i=0;i<str.length;i++){
    if(alphabet.indexOf(str[i])>-1){
    decodedStr +=shift(str[i]);
    }else{
      decodedStr +=str[i];
    }
  }
  return decodedStr;
}
function shift(str){
  let n=(alphabet.indexOf(str)+13)%alphabet.length;
  return alphabet[n];
}
console.log(rot13("GUR DHVPX OEBJA SBK WHZCF BIRE GUR YNML QBT."));
1 Like

Y’all, these are such good solutions! Nice one! :partying_face:

Here’s my two solutions:

With Character Chart Object

const CHARACTER_CHART = {
  A: 'N',
  B: 'O',
  C: 'P',
  D: 'Q',
  E: 'R',
  F: 'S',
  G: 'T',
  H: 'U',
  I: 'V',
  J: 'W',
  K: 'X',
  L: 'Y',
  M: 'Z',
  N: 'A',
  O: 'B',
  P: 'C',
  Q: 'D',
  R: 'E',
  S: 'F',
  T: 'G',
  U: 'H',
  V: 'I',
  W: 'J',
  X: 'K',
  Y: 'L',
  Z: 'M'
};

function rot13(encodedStr) {
  let decodedStr = ""
  for (let i=0; i < encodedStr.length; i++) {
    const char = encodedStr[i];
    if (CHARACTER_CHART.hasOwnProperty(char)) {
      decodedStr += CHARACTER_CHART[char];
    } else {
      decodedStr += char;
    }
  }
  return decodedStr; // Array to String
}

With character codes

const ROTATION = 13;
function rot13(str) {
  let decodedStr = "";
  for (let i = 0; i < str.length; i++) {
    const char = str[i];
    const charCode = str.charCodeAt(i);
    if (/[A-M]/.test(char)) {
      decodedStr += String.fromCharCode(charCode + ROTATION);
    } 
    else if (/[N-Z]/.test(char)) {
      decodedStr += String.fromCharCode(charCode - ROTATION);
    }
    else {
      decodedStr += char;
    }
  }
  return decodedStr;
}
3 Likes

My original version:

function rot13(str) {
  let code = "";
  let decode = "";
  let decodeStr = "";

  for (let char = 0; char < str.length; char++) {

    code = str.charCodeAt(char); // convert char to ASCII value

    // ASCII code for A is 65 and for Z it is 90
 
    if (code >= 65 && code <= 90){
      decode = code - 13;
      if (decode < 65) {
        decode = (90 - (65 - decode)) + 1; // If past A start at Z
      }
      decodeStr += String.fromCharCode(decode);
    }
    else {
      decodeStr += String.fromCharCode(code);
    }

  }
  return decodeStr;
}


console.log(rot13("SERR PBQR PNZC"));

But this version encodes and decodes by adding 13. Learned this from Asif Dawood

// Encode and Decode
function rot13(str) {
  let code = "";
  let decode = "";
  let decodeStr = "";

  for (let char = 0; char < str.length; char++) {

    code = str.charCodeAt(char);

    if (code >= 65 && code <= 90){
      decode = code + 13;
      if (decode > 90){
        decode = (65 + (decode - 90)) - 1; // If past Z start at A
      }
      decodeStr += String.fromCharCode(decode);
    }

    else {
      decodeStr += String.fromCharCode(code);
    }

  }
  return decodeStr;
}


console.log(rot13("SERR PBQR PNZC"));

console.log(rot13("FREE CODE CAMP"));
1 Like

Here’s mine:

function rot13(str) {
  const SHIFT = 13;
  const START = 'A'.charCodeAt();
  let alpha = /[a-z]/i;
  let result = '';
  
  for (let i = 0; i < str.length; i++) {
    // If the character is alphabetical 
    if (alpha.test(str[i])) {
        // Get the character code
        let charCode = str[i].charCodeAt();
        // If the character code is less than 'A', add the shift; otherwise subtract the shift
        if (charCode - SHIFT < START) {
            result += String.fromCharCode(charCode + SHIFT);
        } else {
            result += String.fromCharCode(charCode - SHIFT);
        } 
    }
    // If the character is non-alphabetical do not apply shift
    else {
        result += str[i];
    }
  }
  return result;
}

My code using regex and charcode and a variable for shift. small caps and large are allowed

function convertToCipher(str, shift) {
  let cipheredStr = "";
  for (let i = 0; i < str.length; i++) {
    if (/[A-Z]/.test(str[i])) {
      let newCapCode = str.charCodeAt(i) + shift;

      if (newCapCode > 90) {
        newCapCode = newCapCode - 26;
      }
      cipheredStr += String.fromCharCode(newCapCode);
    } else if (/[a-z]/.test(str[i])) {
      let newSmallCode = str.charCodeAt(i) + shift;

      if (newSmallCode > 122) {
        newSmallCode = newSmallCode - 26;
      }
      cipheredStr += String.fromCharCode(newSmallCode);
    } else {
      cipheredStr += str[i];
    }
  }
  return cipheredStr;
}

console.log(
  convertToCipher("Gur Dhvpx Oebja Sbk Whzcf bire gur Ynml Qbt.", 13)
);

So, here’s my solution also! :smiley:
I’ve used something called “periodic boundary condition” to manage the shift and allow both positive (encrypt) and negative (decrypt) shifts

function shiftCipher(msg, shift) {
  const alphabet = ['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']
  let ROTMsg="";
  const arrayMsg = msg.split("");

  for (let i=0; i<arrayMsg.length; i++){
    const char = arrayMsg[i];
    const charInAlphabet = (/[a-z]/i).test(char)
    if (charInAlphabet){
      var index = alphabet.indexOf(char);
      const signal = shift/Math.abs(shift);
      if (index+shift >= 0){
        var newIndex = (index+shift)%alphabet.length
      } 
      else {
        var newIndex = alphabet.length - (signal*(index+shift))%alphabet.length
      }
      ROTMsg += alphabet[newIndex];
    } 
    else {
      ROTMsg += char;
    }
    // Verbose / Debugging :v
    // console.log(`${char}: ${(/[a-z]/i).test(char)}. ${index} => ${(index+shift)%alphabet.length} = ${alphabet[newIndex]}. ${ROTMsg}`); 
  }
  return ROTMsg;
}

function ROT13(msg) {
  return shiftCipher(msg, 13);
}

Oh, using integers and unicode table was cool

1 Like

my solution

const rot13 = str => str.replace(/[a-z]/gi, letter => String.fromCharCode(letter.charCodeAt(0) + (letter.toLowerCase() <= ‘m’ ? 13: -13)));

this one liner will work for both upper and lowercase letters, enjoy :grinning:

% – of course! brilliant, thanks for sharing!

1 Like

Hi all,
This is my solution:

function rot13(str) {

  let decoded = "";

  // go through the string
  for (let i = 0; i < str.length; i++) {
    // check if the char is alpha
    if (str[i] >= "A" && str[i] <= "Z") {
      // transform
      let temp = String.fromCharCode(((str[i].charCodeAt(0) - 13 + 65) % 26) + 65);
      decoded += temp;
    }
    // if the char is not alpha, add it as it is
    else {
      decoded += str[i];
    }
  }
  
  return decoded;
}
1 Like

hi all, my solution:

let newValue = []
const rot13Key = 13
function rot13(str) {
const newStr = []
  str = str.toUpperCase().split("")
  for (const value of str) {
    const oldValue = value.charCodeAt(0)
    if (oldValue >= 65 && oldValue <= 77) {
      newValue = oldValue + rot13Key
    } else if (oldValue > 77 && oldValue <= 90) {
      newValue = oldValue - rot13Key
    } else {
      newValue = oldValue
    }
    newStr.push(String.fromCharCode(newValue))
    str = newStr.join("")
  }
  return str;
}
1 Like

Here is my solution.
You can give the rot13 function a second argument to shift the Alphabet , but you don’t need to.

const alphabet=['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']
 
function shiftAlphabet(shift){
  let shiftedAlphabet=[...alphabet]
  for(let i=shift; i >0; i--){
    shiftedAlphabet.push(shiftedAlphabet.shift());
     }
   return shiftedAlphabet;
 }


 function replaceLetter(string,shift){

   let index=alphabet.indexOf(string)
    return shiftAlphabet(shift)[index]
 }
 
 function rot13(str,shift=13) {
   let returnArray=[]
   
   for (const letter of str) {
    returnArray.push(letter.replace(/[A-Z]/,replaceLetter(letter,shift)));
  }
   return returnArray.join("");
 }
console.log(rot13("FREE CODE CAMP",8))
//encode with every value
console.log(rot13("NZMM KWLM KIUX",18))
//decode with (26-encode value)

rot13("SERR PBQR PNZC");
1 Like