Skip to content

Instantly share code, notes, and snippets.

@Driim
Last active April 4, 2020 14:37
Show Gist options
  • Save Driim/e23871472539de70796d37567acff8b7 to your computer and use it in GitHub Desktop.
Save Driim/e23871472539de70796d37567acff8b7 to your computer and use it in GitHub Desktop.
The solution of the coder problem
const fs = require('fs');
const readline = require('readline');
const defaultKeys = {
1: ['a', 'b', 'c'],
2: ['d', 'e', 'f'],
3: ['g', 'h', 'i'],
4: ['j', 'k', 'l'],
5: ['m', 'n', 'o'],
6: ['p', 'q', 'r', 's'],
7: ['t', 'u', 'v'],
8: ['w', 'x', 'y', 'z'],
}
function keysToMap(keys) {
const map = new Map();
Object.keys(keys).forEach((key) => {
keys[key].forEach((letter, clicks) => {
map.set(letter, { key, clicks });
})
})
return map;
}
function encode(message, keys) {
const keyMap = keysToMap(keys);
return [...message]
.reduce((result, letter, i) => {
const char = letter.toLowerCase();
const { key, clicks } = keyMap.get(char);
const code = (clicks + i + 1) % keys[key].length;
const encoded = (char !== letter)
? keys[key][code].toUpperCase()
: keys[key][code];
return result.concat(encoded);
}, '');
}
function decode(message, keys) {
const keyMap = keysToMap(keys);
return [...message]
.reduce((result, letter, index) => {
const char = letter.toLowerCase();
const { key, clicks } = keyMap.get(char);
const code = keys[key].findIndex((_value, i) => {
return (i - clicks + 1 + index) % keys[key].length === 0
});
const decoded = (char !== letter)
? keys[key][code].toUpperCase()
: keys[key][code];
return result.concat(decoded);
}, '');
}
async function run() {
const args = process.argv.slice(2);
switch (args[0]) {
case 'file': {
let keys = defaultKeys;
const file = args[1];
if (!file) {
throw new Error('need file');
}
const keysFile = args[2];
if (keysFile) {
keys = JSON.parse(await fs.promises.readFile(keysFile));
}
const fileStream = fs.createReadStream(file);
const lines = readline.createInterface({
input: fileStream,
crlfDelay: Infinity
});
lines.on('line', (line) => {
if (line === '#')
return;
console.log(decode(line, keys));
});
break;
}
case 'test': {
/*
* I decided not to use assert, instead I made the tests more visual.
*/
console.log('\nEncoding Tests');
console.log(`ABCD encoded: ${encode('ABCD', defaultKeys)} - BACE`);
console.log(`IhateSMS encoded: ${encode('IhateSMS', defaultKeys)} - GgaudQNS`);
console.log(`ccd encoded: ${encode('ccd', defaultKeys)} - abd`);
console.log('\nDecoding Tests');
console.log(`BACE decoded: ${decode('BACE', defaultKeys)} - ABCD`);
console.log(`GgaudQNS decoded: ${decode('GgaudQNS', defaultKeys)} - IhateSMS`);
console.log(`abd decoded: ${decode('abd', defaultKeys)} - ccd`);
break;
}
default: {
throw new Error('You should call: "node coder.js test" or "node coder.js file <input> <keymap> keymap is optional"');
}
}
}
run();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment