JavaScript Playfair Cipher

After learning about objects, arrays, and loops this week on the Full-Stack Engineer Career Path, I decided to practice what I had learned so far. So, I set out to code a Playfair Cipher. It wound up not using objects, but was definitely some good practice for the other two.

Those unfamiliar with the Playfair Cipher can find more information on that here: Playfair cipher - Wikipedia

I was thinking this project may take me all day, and possibly even some on the weekend, but I was very happy to have it working in about 2.5 hours this morning! It’s still essentially the very first version of this (I have made a few tweaks throughout the afternoon, so I’ve labeled it version 0.1.1).

As laid out in the readme, I still have some things I would like to add to this script to develop it, but I would love to hear from the community about this first version as well. Are there any ways this code could be refined to be simpler or more efficient? Any concepts I’ve not yet learned that could make this more powerful etc? Am I exhibiting any bad habits in this code that I need to stop?

This is the first project I’ve come up with and made myself outside of any lessons. I was very pleased to not have to cheat and look up how to accomplish any of the core logic, but I will admit I found the removeDuplicateCharacters function on Stack Overflow. I wanted to focus on figuring out the actual loop logic and array structures, and not spend too much time on string manipulation, but I am going to spend some time researching all of the “ingredients” of that function so that I can still learn from it.

My code is below, and I will also link to the readme on GitHub:

/*Playfair Cipher using a 6x6 grid to support numbers*/
//Get input and passkey
let input = 'secret message to encode';
let passkey = 'old tavern';
let output = '';
const gridChars = 'abcdefghijklmnopqrstuvwxyz0123465789';

//Removes duplicate characters from string. Will need this function later.
const removeDuplicateCharacters = (string) => {
    return string
        .split('')
        .filter(function(item, pos, self) {
        return self.indexOf(item) == pos;
        })
        .join('');
       }

// Clean input
    input = input.toLowerCase();
    input = input.replace(/[^a-zA-Z0-9]/g, '');
if (input.length%2 != 0) {
    input += 'z';
};

//Group characters into pairs for encoding
let inputArray = [];
for (let i = 0; i < input.length; i += 2) {
    let subArray = [input[i], input[i+1]];
    inputArray.push(subArray);
};

//Clean passkey (needs no spaces, special characters, or duplicate characters)
    passkey = passkey.toLowerCase();
    passkey = passkey.replace(/[^a-z0-9]/g,'');
    passkey = passkey += gridChars;
    passkey = removeDuplicateCharacters(passkey);

//Generates playfair grid
let playfairArray = [];
for (let i = 0; i < passkey.length; i += 6) {
    let subArray = [passkey[i], passkey[i+1], passkey[i+2], passkey[i+3], passkey[i+4], passkey[i+5]];
    playfairArray.push(subArray);
}

// need to find playfair coordinates of input character pairs stored in each input subarray, stay in same playfair subarray and switch indexes
for (i = 0; i < inputArray.length; i++) {
    let char1 = inputArray[i][0];
    let char2 = inputArray[i][1];
    let pos1;
    let pos2;
    let row1;
    let row2;
    for (y = 0; y < playfairArray.length; y++) {
        for (x = 0; x < playfairArray[y].length; x++) {
            if (char1 === char2 && char1 === playfairArray[y][x]) {
                pos1 = x;
                pos2 = x;
                row1 = y;
                row2 = y;
            } else if (char1 === playfairArray[y][x]) {
                pos2 = x;
                row1 = y;
            } else if (char2 === playfairArray[y][x]) {
                pos1 = x;
                row2 = y;
            }
        }
    }
    output += playfairArray[row1][pos1] + playfairArray[row2][pos2];
}

console.log(output);

After tinkering a little bit more over the weekend, I am pleased to issue an update to version 0.2 of my Playfair Cipher!

This project now utilizes objects, showcasing all three of the concepts I’ve learned over the past week.

A few things I learned in this process are:

  • isolate tasks to only tackle one thing at a time (my first version was using simpler logic and thus could accomplish two things in one particular step, but this caused the code to be very limited and not robust)
  • sometimes when you need to do the same thing but backwards, the steps you need to reverse are not the ones you initially thought

This v0.2 handles all of the rules for character/coordinate manipulation, so it is no longer a “simplified version” of a Playfair Cipher. The code has been packaged up into two separate functions now, encrypt and decrypt. Calling either function utilizes the input and passkey variables. The encrypt function can take any message you like, and will output the encrypted version of your message. In order for the decrypt function to properly work, of course you’ll need to pass in a message that has been encrypted either by using this script, or by following the same rules.

The code has now gone from about 75 lines to around 200, so I will link to the script on GitHub, but refrain from posting the whole thing here.

Hey, this sounded interesting and I wanted to look at the code but your Github link 404ed. Did you delete the repository or mark it private?

Hey, sorry I’m just seeing this! I hadn’t learned git real well yet when I set all this up.

Here is the link to the repository which should work: GitHub - quinton-c/playfaircipher: Inspired by the National Treasure movies, I have been having fun with Playfair Ciphers since about middle school. I always wanted to build an auotmated one, so now that I am learning JavaScript, I have!