Problem
I don’t think the solution Codecademy provided for problem number 3 solves for the requirements they gave… am I crazy???
Requirement
A shift cipher takes a plain text message and shifts each letter forward in the alphabet by a given number. For example, a shift cipher with a shift of 1
would turn the string 'hello'
to 'ifmmp'
.
Create a class ShiftCipher
that takes the numerical value of the shift as a constructor parameter. The class should have two methods:
encrypt
: takes a plain text string and returns a capitalized string with each letter shifted forward in the alphabet based on the set shift value.decrypt
: takes an encrypted message and returns a lower case string with each letter shifted back in the alphabet based on the set shift value.- In both methods, any character outside the alphabet should remain the same.
- But if a character is shifted outside the alphabet in either direction it should be wrapped around to the other side. For example, encrypting a
y
with a shift of4
results inC
and decrypting anA
with a shift of1
result inz
.
Codecademy Provided Solution
// Write class below
class ShiftCipher {
constructor(shift){
this.shift = shift;
}
encrypt(plainString) {
let encryptString = '';
const tempString = plainString.toUpperCase();
for (let i=0; i < tempString.length; i++) {
let charNum = tempString.charCodeAt(i);
if (charNum <= 90 && charNum >= 65) {
charNum += this.shift;
if (charNum > 90) {
charNum -= 26;
}
}
encryptString += String.fromCharCode(charNum);
}
return encryptString;
}
decrypt(encryptString) {
let decryptString = '';
const tempString = encryptString.toLowerCase();
for (let i=0; i < tempString.length; i++) {
let charNum = tempString.charCodeAt(i);
if (charNum <= 122 && charNum >= 97) {
charNum -= this.shift;
if (charNum < 97) {
charNum += 26;
}
}
decryptString += String.fromCharCode(charNum);
}
return decryptString;
}
}
// Test it
let myString = 'I am a god';
console.log(`ORIGINAL STRING: ${myString}`);
const shiftCipher1 = new ShiftCipher(1);
let encryptedString = shiftCipher1.encrypt(myString);
console.log(`ENCRYPTED STRING: ${encryptedString}`);
// Should print "J bn b hpe"
// Actually prints "J BN B HPE"
let decryptedString = shiftCipher1.decrypt(encryptedString);
console.log(`DECRYPTED STRING: ${decryptedString}`);
// Should print "I am a god'
// Actually prints "i am a god"
console.log(`ARE THEY THE SAME? ${myString === decryptedString}`);
My Solution
… I actually think this solves for the requirements:
// function that returns whether a char code is associated with an upper case letter, lower case letter, or not a letter
function letterCase(charCode) {
if (charCode >= 65 && charCode <= 90) {
return 'upper';
} else if (charCode >= 97 && charCode <= 122) {
return 'lower';
} else {
return 'not a letter';
}
}
// function that returns whether a char code is in one of the letter ranges
function isALetter(charCode) {
if ((charCode >= 65 && charCode <= 90) ||
(charCode >= 97 && charCode <= 122)) {
return true;
} else {
return false
}
}
function switchCase(charCode, charCase) {
let newCharCode = 0;
if (charCase = 'upper') newCharCode = charCode + 32;
if (charCase = 'lower') newCharCode = charCode - 32;
return newCharCode;
}
// define Shift Cipher class
class ShiftCipher {
constructor(shift) {
this.shift = shift;
}
encrypt(string) {
// convert the string to lower case so the logic is easier
let lowerString = string.toLowerCase();
// create array to track shifted character codes
let encryptedCharCodeArray = [];
// iterate through each character in the string
for (let i = 0; i < string.length; i++){
let originalCharCode = string.charCodeAt(i);
// console.log(`Original char code: ${originalCharCode}`);
let originalCase = letterCase(originalCharCode);
// console.log(`Original case: ${originalCase}`);
let lowerCharCode = lowerString.charCodeAt(i);
// console.log(`Lower char code: ${lowerCharCode}`);
let newCharCode = 0;
// Should not be shifting if it's not a letter
if (!isALetter(originalCharCode)) {
newCharCode = originalCharCode;
} else {
// Shifting logic
newCharCode = lowerCharCode + this.shift;
if (!isALetter(newCharCode)) {
// If the shifted character code is not in the letter range, bring back into range
if (newCharCode < 97) {
newCharCode = 122 - (96 - newCharCode);
if (originalCase == 'lower') newCharCode = switchCase(newCharCode, originalCase);
}
if (newCharCode > 122) {
newCharCode = 96 + (newCharCode - 122);
if (originalCase == 'lower') newCharCode = switchCase(newCharCode, originalCase);
}
} else {
if (originalCase == 'upper') newCharCode = switchCase(newCharCode, 'lower');
}
}
// console.log(`New char code: ${newCharCode}`);
// console.log('---')
encryptedCharCodeArray.push(newCharCode);
}
// return a new string using spread charCodes from encryptedCharCodeArray
// console.log(encryptedCharCodeArray);
return String.fromCharCode(...encryptedCharCodeArray);
}
decrypt(string) {
// convert the string to lower case so the logic is easier
let lowerString = string.toLowerCase();
// create array to track shifted character codes
let decryptedCharCodeArray = [];
// iterate through each character in the string
for (let i = 0; i < string.length; i++){
let originalCharCode = string.charCodeAt(i);
// console.log(`Original char code: ${originalCharCode}`);
let originalCase = letterCase(originalCharCode);
// console.log(`Original case: ${originalCase}`);
let lowerCharCode = lowerString.charCodeAt(i);
// console.log(`Lower char code: ${lowerCharCode}`);
let newCharCode = 0;
// Should not be shifting if it's not a letter
if (!isALetter(originalCharCode)) {
newCharCode = originalCharCode;
} else {
// Shifting logic
newCharCode = lowerCharCode - this.shift;
if (!isALetter(newCharCode)) {
// If the shifted character code is not in the letter range, bring back into range
if (newCharCode < 97) {
newCharCode = 122 - (96 - newCharCode);
if(originalCase === 'lower') newCharCode = switchCase(newCharCode, originalCase);
}
if (newCharCode > 122) {
newCharCode = 96 + (newCharCode - 122);
if (originalCase == 'lower') newCharCode = switchCase(newCharCode, originalCase);
}
} else {
if (originalCase == 'upper') newCharCode = switchCase(newCharCode, 'lower');
}
}
// console.log(`New char code: ${newCharCode}`);
// console.log('---')
decryptedCharCodeArray.push(newCharCode);
}
// return a new string using spread charCodes from encryptedCharCodeArray
// console.log(decryptedCharCodeArray);
return String.fromCharCode(...decryptedCharCodeArray);
}
}
// Test this
let myString = 'I am a god';
console.log(`ORIGINAL STRING: ${myString}`);
const shiftCipher1 = new ShiftCipher(1);
let encryptedString = shiftCipher1.encrypt(myString);
console.log(`ENCRYPTED STRING: ${encryptedString}`);
let decryptedString = shiftCipher1.decrypt(encryptedString);
console.log(`DECRYPTED STRING: ${decryptedString}`);
console.log(`ARE THEY THE SAME? ${myString === decryptedString}`);