-
Notifications
You must be signed in to change notification settings - Fork 0
/
scrabble-lookup.es6
executable file
·128 lines (111 loc) · 3.23 KB
/
scrabble-lookup.es6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#!/usr/bin/env node
/* eslint no-debugger: "warn" */
/* eslint brace-style: ["error", "stroustrup"] */
import parseArgs from 'minimist';
import path from 'path';
import fs from 'fs';
const dictFile = '/usr/share/dict/american-english';
const wordsModuleFile = './words.js';
let words = {};
/* ********************************
* generate the words module
*/
const charFrequency = word => Array.from(word.toLowerCase())
.reduce((freq, char) => {
freq[char] = (freq[char] || 0) + 1; // eslint-disable-line no-param-reassign
return freq;
}, {});
const processWord = (word) => {
if (/[^a-z]/.test(word)) return;
const freq = charFrequency(word);
const key = Array.from(word.toLowerCase()).sort().join('');
if (key in words) {
words[key].words.push(word);
}
else {
words[key] = { freq, words: [word] };
}
};
const writeWordFile = (file) => {
debugger;
Object.keys(words).forEach((key) => {
words[key].words = Array.from(new Set(words[key].words.map(w => w.toLowerCase())));
});
const data = `/* generated from ${file} on ${new Date().toString()} */\n`
+ `const words = ${JSON.stringify(words)};\n`
+ 'module.exports = words;\n';
/*
fs.promises
.writeFile(wordsModuleFile, data)
.then(() => { console.log(`${wordsModuleFile} complete.`); });
*/
fs.writeFileSync(wordsModuleFile, data);
};
const generateWordsModule = (file = dictFile) => {
debugger;
/*
const rl = readline.createInterface({ input: fs.createReadStream(file) });
rl.on('line', processWord);
rl.on('close', writeWordFile);
*/
const content = fs.readFileSync(file);
content.toString().split('\n').forEach(processWord);
writeWordFile(file);
/*
fs.readFile(file, (err, data) => {
debugger;
if (err) throw err;
data.toString().split('\n').map(processWord);
writeWordFile();
});
*/
};
/* ********************************
* lookup
*/
if (fs.existsSync(path.join(__dirname, wordsModuleFile))) {
words = require(wordsModuleFile); // eslint-disable-line global-require, import/no-dynamic-require
}
const lookup = (letters) => {
const freq = charFrequency(letters);
const re = new RegExp(`^[${Object.keys(freq).join('')}]{3,}$`);
/* eslint-disable no-param-reassign */
return Object.keys(words)
.filter((key) => {
const frq = words[key].freq;
return re.test(key)
&& Object.keys(frq).every(c => frq[c] <= freq[c]);
})
.reduce((wrds, key) => wrds.concat(words[key].words), [])
.sort()
.reduce((map, word) => {
map[word.length] = (map[word.length] || []).concat(word);
return map;
}, {});
/* eslint-enable no-param-reassign */
};
const main = () => {
const usage = `usage: ${process.argv[1].replace(/.+\//, '')} [-h] <-g dictionaryFile | tiles>
where: -g -- generate word list from dictionary (default ${dictFile})
`;
const args = parseArgs(process.argv.slice(2), {
boolean: ['h', 'g'],
});
if (args.h) {
console.log(usage);
}
else if (args.g) {
generateWordsModule(args._[0]);
}
else {
if (!words) {
console.log('Words module does not exist... generating it.');
generateWordsModule();
}
console.log(lookup(args._[0]));
}
};
module.exports = lookup;
if (!module.parent) {
main();
}