Javascript Practice: Classes - Shift Cipher Solution Help (Code Challenge)

Javascript Practice: Classes

My question is: is there a way anyone came up with for solving the encrypt and decrypt methods that doesn’t involve converting the string into an array and iterating through it?

Bonus question: is it better to do so?

Here’s my solution:

lass ShiftCipher {
  constructor(shifter) {
    this.shifter = shifter;
  }

  encrypt(string) {
    let upped = string.toUpperCase();
    let strArr = [];
    for (let i = 0; i < upped.length; i++) {
      strArr.push(upped[i]);
    }
    return strArr
      .map((char) => {
        if (char.charCodeAt() > 90 || char.charCodeAt() < 65) return char;
        if (char.charCodeAt() + this.shifter > 90) {
          return String.fromCharCode(char.charCodeAt() + this.shifter - 26);
        }
        return String.fromCharCode(char.charCodeAt() + this.shifter);
      })
      .join("");
  }

  decrypt(string) {
    let downed = string.toLowerCase();
    let strArr = [];
    for (let i = 0; i < downed.length; i++) {
      strArr.push(downed[i]);
    }
    return strArr
      .map((char) => {
        if (char.charCodeAt() < 97 || char.charCodeAt() > 122) return char;
        if (char.charCodeAt() - this.shifter < 97) {
          return String.fromCharCode(char.charCodeAt() - this.shifter + 26);
        }
        return String.fromCharCode(char.charCodeAt() - this.shifter);
      })
      .join("");
  }
}

const twoShift = new ShiftCipher(2);
console.log(twoShift.encrypt('I love to code!'))
console.log(twoShift.decrypt("K <3 OA RWRRA"));
1 Like

Also, does anyone have any recommendations to make my code cleaner (i.e. to have less repeat code)?

No expert here, from my understanding, string operations are very expensive. They use both memory and clock ticks. Arrays, on the other hand are a data structure intended to be accessed and mutated, while strings can only be accessed, not mutated. That would make their (array) operations more optimized. I can see no reason NOT to use an array and its methods for this type of problem. Moreover it may offer improved readability and it be readily discernible what is going on when we return a year later to review/update this code.

1 Like

hi javaace96747,

I like your solution where you handled the wrap. It was simpler than mine. One shortcut I took when converting the message into an array of character codes is:

  let charCodeArray = [...message]

Where “…” is the spread operator in JS. In this case, the individual characters of the message are spread out as members of the array. Then my for-each loop took care of converting them to character codes and doing the shifting very similar to your code.

1 Like

So this is what I was able to come up with that managed to avoid the use of Arrays as the original poster questioned.

For each method, I simply set a variable for both upper and lowercase. From there, I run a loop on the string with an additional IF statement to compare the lower and uppercase values.

Only A-Z and a-z will NOT be the same as all spaces and punctuation are identical in upper and lower case.

Code within the IF statement reads:
If uppercase and lowercase are NOT the same (letters), then transcribe the string to Unicode, add the number parameter and then (if necessary) loop the Unicode (adding or subtracting 26).

Else if they are the same (numbers, punctuation, spaces) leave as is.

Either case will then CONCAT all loop outputs to an empty string variable and return that string.



class ShiftCipher {

    constructor(number) {

        this._number = number;

    }

    get number() {

        return this._number;

    }

    encrypt(estring) {

        let upper = estring.toUpperCase();

        let lower = estring.toLowerCase();

        let encrypted = '';

        for (let i = 0; i < upper.length; i++) {

            if (upper[i] !== lower[i]) {

                let toUnicode = upper.charCodeAt(i) + this.number;

                if (toUnicode > 90) {

                    toUnicode = toUnicode - 26;

                }

                let toAlpha = String.fromCharCode(toUnicode);

                encrypted = encrypted.concat(toAlpha);

            } else {

                encrypted = encrypted.concat(upper[i]);

            }

        }

        return encrypted;

    }

    decrypt(dstring) {

        let upper = dstring.toUpperCase();

        let lower = dstring.toLowerCase();

        let decrypted = '';

        for (let i = 0; i < lower.length; i++) {

            if (upper[i] !== lower[i]) {

                let toUnicode = lower.charCodeAt(i) - this.number;

                if (toUnicode < 97) {

                    toUnicode = toUnicode + 26;

                }

                let toAlpha = String.fromCharCode(toUnicode);

                decrypted = decrypted.concat(toAlpha);

            } else {

                decrypted = decrypted.concat(lower[i]);

            }

        }

        return decrypted;

    }

}

Minorly improved readability of and ease-of-understanding code by replacing,

    let upped = string.toUpperCase();
    let strArr = [];
    for (let i = 0; i < upped.length; i++) {
      strArr.push(upped[i]);
    }

with

let strArr = [...string.toUpperCase()];

This also uses more modern ECMAScript syntax and reduces overall code written.

1 Like