Need a hint for JS Caesar exercise

I’ve gotten the very basic solution working where if check if the character is a letter and only then, shift it “shift” amount but towards the end of the alphabet my code is shifting into punctuation. I’m trying to figure out how to check again and see if the newly-shifted character is still in the alphabet but I’m stuck. If anyone can give me some kind of hint, I’d really appreciate it. This one is taking me to the limit! Here’s my code:

const caesar = function(string, shift) {
    let result = "";
    // loop through string
    for (let i = 0; i < string.length; i++){
        // turn letters into character codes 
        let unicode = string.charCodeAt(i);
        // add shift to original character Number IF CHARACTER IS LETTER ONLY!!!!
        
        // Make sure shift goes back to start of alphabet
        if ((unicode >= 65 && unicode <= 90) || (unicode >= 97 && unicode <= 122)) {
            unicode += shift;
        }
        
        // convert back into letters
        let cypher = String.fromCharCode(unicode);
        // add the new string each character to result
        result += cypher;
    } 

    return result;
}
1 Like

Hi, after the shift you can do again (inside the if and affter the shift)

 if (unicode > 90  || unicode>122){
     unicode -=amountOfLetters;
 }

if the result of the shift is the next character after “z”, this should transform it to “a”.

Is important to note:
this only work if the shift is between 0 and 25.
Remember shift of 26 is equivalent to a shift of 0, 27 to 1, 52 to 0, etc

So you must find the equivalent of any shift to a shift between 0 and 25 before use this.
These equivalences are the remainder of the division between the shift and amounOfLeters=26

You can achieve this with

let between0and25 = shift % 26

this maps any positive number to a number between 0 and 25

The % doesnt work with negative shifts because return values between -25 and 0
But also you can search a relation between negative shifts and numbers between 0 and 25.
-1 changes “a” to “z”,so is equivalent to a shift of 25
-2 changes “a” to “y”, ,so is equivalent to a shift of 24,
-25 changes “a” to “b”, ,so is equivalent to a shift of 1,
etc

So the trick seems to be work in the shift value to make easier the shifting

Hope this will help you.

1 Like

Thanks, Fernando! I was able to incorporate the modulus to handle large shift numbers, and I also made a new if statement inside the previous one that looks for if the result is outside of the alpha characters and then downshifts it by 26. I’m still having a problem though, where in one of the tests caesar("Hello, World!", 75) results in "Ebiil, nloia!" instead of "Ebiil, Tloia!". My guess is that the shift of 75 (even after the modulus operation) is scooting the first letter of the second word into the lowercase letters and thus my second if check doesn’t catch it and thinks everything is fine. The only thing I can think of to do is write a series of if checks that determine if the letter is supposed to be uppercase or lowercase and then use a + or - to wrap the letter around its set of either unicode 65-90 OR 92 and 122. But that seems really tedious and not at all elegant, so I’m wondering if there’s a much better way to do this. Here’s my code:

const caesar = function(string, shift) {
    let result = "";

    // handle large shift numbers
    if (shift > 26){
        shift = shift % 26;
    }
    
    // loop through string
    for (let i = 0; i < string.length; i++){
        // turn letters into character codes 
        let unicode = string.charCodeAt(i);
        // add shift to original character Number IF CHARACTER IS LETTER ONLY!!!!
               
        if ((unicode >= 65 && unicode <= 90) || (unicode >= 97 && unicode <= 122)) {
            let newUnicode = unicode += shift;
            // Make sure shift goes back to start of alphabet
            if ((newUnicode > 122) || (newUnicode >= 91 && newUnicode <= 96)){
                newUnicode -= 26;
            } else if (newUnicode < 65){
                newUnicode += 26;
            }
            unicode = newUnicode;
        }        
        // convert back into letters
        let cypher = String.fromCharCode(unicode);
        // add the new string each character to result
        result += cypher;
    } 
    return result;
}

Hi i think the error happens when the shift is big enough (in this case is 23)

In the if statement

if ((newUnicode > 122) || (newUnicode >= 91 && newUnicode <= 96))

both conditions are false because this shift go from a valid letter (“W”) to another (“n”), so doest correct the shift

You can add a function that tells you if the the case is the same between the letter shifted and the original, if isn’t the code must be corrected.

1 Like

How would I go about making a function that did that? I’m totally lost.

I tried making a group of if statements that check if the old unicode is lowercase or uppercase, and then if the new unicode variable has gone outside of the correct case range…or at least I thought I did. Basically I broke my function and it no longer passes most of the tests. I have no idea what’s wrong with my logic here. Any help would be appreciated.

const caesar = function(string, shift) {
    let result = "";

    // handle large shift numbers
    shift = shift % 26;

    // loop through string
    for (let i = 0; i < string.length; i++){
        // turn letters into character codes 
        let unicode = string.charCodeAt(i);
        
        // add shift to original character Number IF CHARACTER IS LETTER ONLY!!!!      
        if ((unicode >= 65 && unicode <= 90) || (unicode >= 97 && unicode <= 122)) {
            let newUnicode = unicode += shift;
            // Make sure shift goes back to start of alphabet
            if ((unicode >= 65 && unicode <= 90) && newUnicode > 90){
                newUnicode -= 26;
            } else if ((unicode >= 65 && unicode <= 90) && newUnicode < 65){
                newUnicode += 26;
            } else if ((unicode >= 97 && unicode >= 122) && newUnicode > 122){
                newUnicode -= 26;
            } else if ((unicode >= 97 && unicode >= 122) && newUnicode < 97){
                newUnicode += 26;
            }
            unicode = newUnicode;
        }        
        // convert back into letters
        let cypher = String.fromCharCode(unicode);
        // add the new string each character to result
        result += cypher;
    } 
    return result;
}

you can make a function that tells you if the letter is upper

funtion isUpperCase(letter){
     return letter.toUpperCase ==  letter;
}

if passing to upper case change anything, is because the letter was upper case

and another that compares two letters cases

function sameCase(letter1,letter2){
     return  isUppercase(letter1) == isUpperCase(letter2) 
}

So the comparation must be

let old = string.charAt(i)
let new = String.fromCharCode(unicode)
sameCase(old,new)

probably you must add some check in case you pass to sameCase a char that isnt a letter.

1 Like

Thanks! I’ll see about incorporating some kind of case management function like you’ve described. Any ideas why my latest code seems to have broken the function? I can’t figure out what I’ve done wrong with my logic there.

Would try to go back to the previous version. It’s simpler and you can add changes form there.

also you can add more auxiliar functions to make your code easier to read

let old = string.charAt(i)
 if(isALetter(old)){
       if(new<"a"){
           ....
       }
       else if( (!isALetter(new)  || !sameCase(old , new) )){
               ....
      }
 }

In this way you can know what is doing each function witouth knowing their content.

Note the importance of the function names. IsALetter name is almost a question so you know it should return true if the parameter is a letter.

1 Like

Thanks for all your help! I’ll try that.