Files
quartiles/scripts/build-client-lexicon.mjs
2026-10-26 10:06:30 -04:00

62 lines
2.4 KiB
JavaScript

import fs from 'node:fs';
import { buildWordSet, loadComboWords, getCommonnessScore } from './lexicon-sources.mjs';
// Build a clean, high-frequency recognized vocabulary for client-side unlimited/custom puzzles
// (includes regional spellings and the proper-word allowlist)
const vocabulary = buildWordSet();
// Accept-only words (scripts/combo-words.txt): valid in play, never shown in solution lists
const comboWords = [...new Set(loadComboWords())].filter(w => !vocabulary.has(w)).sort();
console.log('Total vocabulary words:', vocabulary.size);
console.log('Accept-only combo words:', comboWords.length);
// Pack into space-separated string or array
const sortedWords = [...vocabulary].sort();
// One digit (0-4) per word, parallel to RAW_LEXICON. Compresses to almost nothing.
const commonnessDigits = sortedWords.map(w => getCommonnessScore(w)).join('');
const lexiconContent = `// Client-side recognized English words for solver & custom puzzles
// Loaded as a Set for O(1) instantaneous lookup
const RAW_LEXICON = ${JSON.stringify(sortedWords)};
export const DICTIONARY_SET = new Set(RAW_LEXICON);
// Commonness tier per word (4 = most common, 0 = rare), parallel to RAW_LEXICON
const RAW_COMMONNESS = ${JSON.stringify(commonnessDigits)};
const COMMONNESS_MAP = new Map();
for (let i = 0; i < RAW_LEXICON.length; i++) {
const c = RAW_COMMONNESS.charCodeAt(i) - 48;
if (c > 0) COMMONNESS_MAP.set(RAW_LEXICON[i], c);
}
export function getCommonnessScore(word) {
return COMMONNESS_MAP.get(word) || 0;
}
// Accept-only words buildable from pool tiles (generated by
// scripts/find-missing-combo-words.mjs). Space-packed to keep the bundle small.
const RAW_COMBO_WORDS = ${JSON.stringify(comboWords.join(' '))};
export const COMBO_WORD_SET = new Set(RAW_COMBO_WORDS ? RAW_COMBO_WORDS.split(' ') : []);
// Prefix set for lightning fast tree-pruning search (1 to 6 chars)
export const PREFIX_SET = new Set();
for (const word of RAW_LEXICON) {
for (let len = 1; len <= Math.min(word.length, 6); len++) {
PREFIX_SET.add(word.slice(0, len));
}
}
export function isWordValid(word) {
return DICTIONARY_SET.has(word.toLowerCase());
}
// Any word a player may submit: main dictionary + accept-only combo words
export function isAcceptedWord(word) {
const w = word.toLowerCase();
return DICTIONARY_SET.has(w) || COMBO_WORD_SET.has(w);
}
`;
fs.writeFileSync('src/data/lexicon.js', lexiconContent, 'utf8');
console.log('Saved src/data/lexicon.js successfully!');