Skip to content

Commit

Permalink
Clean up, simplify and fix code.
Browse files Browse the repository at this point in the history
  • Loading branch information
w4ffl35 committed Jan 24, 2024
1 parent dc9a957 commit 0ab90ef
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 185 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

192 changes: 19 additions & 173 deletions src/cipher.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,207 +15,53 @@ class Cipher {
this.alpha = props.alpha;
this.trans = [];

// Prepare the keyword based on the provided string in the secret variable
//
// Example: if the keyword "mythology" was used, it would become "MYTHOLOGY"
// after running this._parse
this.key = this._parse(secret)
this.key = [...new Set(this.key.split(''))].join('');

// Remove any duplicate characters from the keyword
//
// Example: the keyword "MYTHOLOGY" would become "MYTHOLG"
this.key = this._distinct(this.key);

// Prepare the cipher based on the key by splitting the key into an array of letters
//
// Example: they key "MYTHOLG" is split into the array
// ["M", "Y", "T", "H", "O", "L", "G"]
this.cipher = this.key.split('');

// Sort the cipher by alphabetical order
//
// now the array is sorted into
// ["G", "H", "L", "M", "O", "T", "Y"]
this.cipher = this.cipher.sort();

// Set the "width" of the cipher.
//
// The cipher is a string with a set number of unique characters.
// In our example, the width is 7
this.width = this.cipher.length;

// Set the "height" of the cipher.
//
// Divide the length of the alphabet by the length of the cipher
// to find its height. In our example, the height is 4
this.height = Math.floor(this.alpha.length / this.cipher.length)+1;

// Create a "keyword" alphabet based on the original alphabet and the keyword
//
// in our example, kAlpha will equal:
/*
MYTHOLGABCDEFGHIJKLMNOPQRSTUVWXYZ
*/
var kAlpha = this.key + this.alpha;
kAlpha = [...new Set(kAlpha.split(''))].join('');

// Remove any repeated letters
//
// in our example, kAlpha becomes:
/*
MYTHOLGABCDEFIJKNPQRSUVWXZ
*/
kAlpha = this._distinct(kAlpha);

// Store keyword alpha as a class property and add padding to the end of it.
//
// In our example:
// 7 * 4 = 28 - 26 + 1 = 3
// An array of length 3 is created, then joined together on a " " blank space character.
// This is added to the kAlpha and stored as a class property.
const padding = Array(Math.abs(this.width * this.height - kAlpha.length) + 1).join(" ");
this.kAlpha = kAlpha + padding;

// ARRANGE THE GRID
//
// Iterate over each letter in the cipher array.
this.cipher.forEach(
(_, i) => {
// get a letter from the keyword alphabet
let letter = this.kAlpha[i];

// get the index of the chosen letter from the cipher
let cipherIndex = this.cipher.indexOf(letter);

// store the character in the transform alpha using the cipher index
//
// In our example, a transform of the following shape is created
// this is used to create an enciphered alphabet
// [-6, -2, -3, 3, 0, 3, 5 ]
this.trans[cipherIndex] = cipherIndex - i;
}
(_, i) => {
let letter = this.kAlpha[i];
let cipherIndex = this.cipher.indexOf(letter);
this.trans[cipherIndex] = cipherIndex - i;
}
);

// Build the encrypted alphabet
//
// In our example, GISHDPXLFRMAJUOEQZTCNWYBKV
this.encryptedAlpha = this._parse(
// Split the keyword into an array
this.kAlpha.split('').map(
(_, i) => {
/*
set keyword alphabet index
_flatIndex transforms the given keyword alpha index into an index which
can be used with a transform.
The max between that number and the kAlpha length becomes the kAlphaIndex.
This operation is performed for each letter in the kAlpha string.
In our example, the
index => flat => kAlpha => kAlphaIndex
transformation for each letter is:
0 => 0 => 6 => 6
1 => 7 => 13 => 13
2 => 14 => 20 => 20
3 => 21 => 27 => 27
4 => 1 => 3 => 3
5 => 8 => 10 => 10
6 => 15 => 17 => 17
7 => 22 => 24 => 24
8 => 2 => 5 => 5
9 => 9 => 12 => 12
10 => 16 => 19 => 19
11 => 23 => 26 => 26
12 => 3 => 0 => 0
13 => 10 => 7 => 7
14 => 17 => 14 => 14
15 => 24 => 21 => 21
16 => 4 => 4 => 4
17 => 11 => 11 => 11
18 => 18 => 18 => 18
19 => 25 => 25 => 25
20 => 5 => 2 => 2
21 => 12 => 9 => 9
22 => 19 => 16 => 16
23 => 26 => 23 => 23
24 => 6 => 1 => 1
25 => 13 => 8 => 8
26 => 20 => 15 => 15
27 => 27 => 22 => 22
*/
let kAlphaIndex = this._max(
this._flatIndex(i) - this.trans[this._flatIndex(i) % this.width],
this.kAlpha.length
)
return this.kAlpha[kAlphaIndex]
}
).join('')
this.kAlpha.split('').map(
(_, i) => {
let kAlphaIndex = this._max(
this._flatIndex(i) - this.trans[this._flatIndex(i) % this.width],
this.kAlpha.length
)
return this.kAlpha[kAlphaIndex]
}
).join('')
);
}

/*
* Remove any repeated letters from the given string
* */
_distinct = (val) => val.split('').filter((item, i, self) => self.indexOf(item) === i).join('')

/*
* Compare two integers and return max if i is greater
* */
_distinct = (val) => [...new Set(val.split(''))].join('')
_max = (i, max) => i > max ? max : i

/*
* Get an index based on the "height" and "width" of the cipher
* */
_flatIndex = (i) => Math.floor(i / this.height) + ((i % this.height) * this.width)

/*
* Adds spaces to the given string
* */
_addSpaces = (s) => this.props.addSpaces ? s.replace(/.{5}/g, '$& ') : s

/*
* Encrypts the given input string
* */
_crypt = (s, alphaA, alphaB) => this._addSpaces(s.split('').map(lttr => alphaA[alphaB.indexOf(lttr)]).join(''))

/*
* Converts the given string to upper-case
* */
_convertCase = (s) => this.props.toUpper ? s.toUpperCase() : s;

/*
* Strip any non-alpha characters from the input string
* */
_stripCharacters = (s) => this.props.stripCharacters ? s.replace(/[^a-zA-Z]/g, '') : s

/*
* Strip any spaces from the input string
* */
_stripSpaces = (s) => this.props.stripSpaces ? s.replace(/ /g, '') : s

/*
* Convert the given string to uppercase, replace non-alpha characters.
* */
_parse = (s) => this._stripCharacters(
this._stripSpaces(
this._convertCase(s)
)
)

/*
* encrypt(string: s): string
*
* Given a plain text string, this function will return an encrypted version of it
* using the _crypt function.
* */
_parse = (s) => this._stripCharacters(this._stripSpaces(this._convertCase(s)))
encrypt = (s) => this._crypt(this._parse(s), this.encryptedAlpha, this.alpha)

/*
* decrypt(string: s): string
*
* Given an encrypted string, this function will return a decrypted version of it
* using the _crypt function.
* */
decrypt = (s) => this._crypt(s, this.alpha, this.encryptedAlpha)
}

module.exports = Cipher;
module.exports = Cipher;
27 changes: 17 additions & 10 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,26 @@ class CipherRunner {

doEncryption = () => {
this.question('Enter a message: ')
.then(message => this.encryptMessage(message))
.then(encrypted => {
console.log(encrypted);
return encrypted;
})
.then(this.decryptMessage)
.then(console.log)
.then(this.doEncryption)
.then(message => this.encryptMessage(message))
.then(encrypted => {
console.log(encrypted);
return encrypted;
})
.then(this.decryptMessage)
.then(console.log)
.then(() => this.question('Do you want to continue? (yes/no): '))
.then(answer => {
if (answer.toLowerCase() === 'yes') {
this.doEncryption();
} else {
this.rl.close();
}
});
}

run = () => this.question('Enter a secret: ')
.then(secret => this.cipher = new C(secret))
.then(this.doEncryption)
.then(secret => this.cipher = new C(secret))
.then(this.doEncryption)
}

const cr = new CipherRunner();
Expand Down

0 comments on commit 0ab90ef

Please sign in to comment.