Search code examples
javascriptcaesar-cipher

How to process negative shifts in Caesars Cipher (Javascript)


I'm trying to pass Odin Projects Caesars Cipher and the test is asking to be able to convert negative shifts. Based off of my current code I am able to shift lower case but I am having some issues with B or W.

it('works with negative shift', function() {
    expect(caesar('Mjqqt, Btwqi!', -5)).toEqual('Hello, World!');

However on return my code spits out

'Hello, =orld!'

So close! I've been trying to figure out what it is but I'm not sure what I'm doing wrong here since the 'H' is working

I've rewritten this thing multiple times and I always end up here. I'm sure it's just a number away or something. However it's beyond what I've known or can comprehend at this point.

Thank you all in advance and sorry for such a simple question.

const caesar = function(message, shift) {
    return message 
    .split("") //splits it into an array
    .map(message => { //does the following to each element in the array
        normalStr = String.fromCharCode(message.charCodeAt())
        prePoint = message.charCodeAt() //gets the charcode of element  
    //if/else checks to see if upper or lower case
    if (prePoint >= 65 && prePoint <= 90) { //upper case
        return String.fromCharCode(((prePoint - 65 + shift) % 26) + 65);
    } else if (prePoint >= 97 && prePoint <= 122){ //lower case
        return String.fromCharCode((prePoint -97 + shift % 26) + 97) 
    }  else {
        return normalStr

        //1 func proc uppoer case
        //1 func proc lowercase
        //1 func proc non upper/lower case
    }})
    .join("")

}

Solution

  • Your code only works for positive caesar shifts, because in
    String.fromCharCode(((prePoint - 65 + shift) % 26) + 65);
    the prePoint - 65 + shift might be below zero (with prePoint = B = 66 and shift = -5 you would get -4)

    You could either fix this by checking if the result of (prePoint - 65 + shift) is negative, and if so, adding 26 to it:

    let newPoint = (prePoint - 65 + shift) % 26;
    if(newPoint < 0) newPoint += 26;
    return String.fromCharCode(newPoint + 65);
    

    (the same for lowercase letters)

    Alternatively you can convert the negative shift into a positive one at the start of your function (a -5 caear shift is the same as a 21 caesar shift):

    if(shift < 0) { shift = 26 + (shift % 26);}
    

    Full example:

    function caesar(message, shift) {
      if (shift < 0) {
        shift = 26 + (shift % 26);
      }
      return message
        .split("") //splits it into an array
        .map(message => { //does the following to each element in the array
          normalStr = String.fromCharCode(message.charCodeAt())
          prePoint = message.charCodeAt() //gets the charcode of element  
          //if/else checks to see if upper or lower case
          if (prePoint >= 65 && prePoint <= 90) { //upper case
            return String.fromCharCode(((prePoint - 65 + shift) % 26) + 65);
          } else if (prePoint >= 97 && prePoint <= 122) { //lower case
            return String.fromCharCode(((prePoint - 97 + shift) % 26) + 97)
          } else {
            return normalStr;
          }
        })
        .join("");
    }
    
    console.log(caesar('Mjqqt, Btwqi!', -5)); // Hello World!