more words
This commit is contained in:
@@ -1,22 +1,9 @@
|
||||
import fs from 'node:fs';
|
||||
import wordlistEnglish from 'wordlist-english';
|
||||
|
||||
const validTwo = new Set([
|
||||
'am', 'an', 'as', 'at', 'be', 'by', 'do', 'go', 'he', 'hi',
|
||||
'if', 'in', 'is', 'it', 'me', 'my', 'no', 'of', 'oh', 'on',
|
||||
'or', 'so', 'to', 'up', 'us', 'we'
|
||||
]);
|
||||
import { buildWordSet } from './lexicon-sources.mjs';
|
||||
|
||||
// Build a clean, high-frequency recognized vocabulary for client-side unlimited/custom puzzles
|
||||
const vocabulary = new Set();
|
||||
for (const word of wordlistEnglish.english) {
|
||||
const w = word.toLowerCase().trim();
|
||||
if (w.length === 2 && validTwo.has(w)) {
|
||||
vocabulary.add(w);
|
||||
} else if (w.length >= 3 && w.length <= 16 && /^[a-z]+$/.test(w)) {
|
||||
vocabulary.add(w);
|
||||
}
|
||||
}
|
||||
// (includes regional spellings and the proper-word allowlist)
|
||||
const vocabulary = buildWordSet();
|
||||
|
||||
console.log('Total vocabulary words:', vocabulary.size);
|
||||
|
||||
|
||||
@@ -466,6 +466,249 @@ slippers|sl-ip-pe-rs|home|Soft shoes worn indoors
|
||||
potatoes|po-ta-to-es|food|Starchy vegetables used for fries
|
||||
sausages|sa-us-ag-es|food|Seasoned meat in a casing
|
||||
pretzels|pr-et-ze-ls|food|Twisted salty baked snacks
|
||||
absolute|ab-so-lu-te|everyday|Complete and total
|
||||
academic|ac-ad-em-ic|education|Relating to school or scholarship
|
||||
accident|ac-ci-de-nt|everyday|Unplanned event that causes harm
|
||||
accidental|ac-ci-den-tal|everyday|Happening by chance
|
||||
accuracy|ac-cu-ra-cy|everyday|Quality of being correct and precise
|
||||
accurate|ac-cu-ra-te|everyday|Correct in every detail
|
||||
activity|ac-ti-vi-ty|everyday|Something you do for fun or a purpose
|
||||
additional|ad-di-tion-al|everyday|Added or extra
|
||||
advertise|ad-ver-ti-se|business|Promote a product publicly
|
||||
agreement|ag-re-em-ent|business|Shared understanding or deal
|
||||
alternative|al-ter-na-tive|everyday|Another possible choice
|
||||
analysis|an-al-ys-is|science|Detailed examination of something
|
||||
announce|an-no-un-ce|everyday|Make known publicly
|
||||
anonymous|ano-ny-mo-us|everyday|Of unknown name
|
||||
appearance|ap-pea-ra-nce|everyday|The way someone or something looks
|
||||
appreciate|ap-pre-ci-ate|emotion|Recognize the value of
|
||||
approach|ap-pr-oa-ch|everyday|Come near to
|
||||
appropriate|ap-pro-pri-ate|everyday|Suitable for the situation
|
||||
argument|ar-gu-me-nt|everyday|Heated disagreement
|
||||
arrangement|ar-ran-ge-ment|everyday|Plan or organized layout
|
||||
assembly|as-se-mb-ly|education|Gathering of people, as at school
|
||||
assistant|as-si-st-ant|jobs|Person who helps another
|
||||
associate|as-so-ci-ate|business|Connect in the mind; a colleague
|
||||
attitude|at-ti-tu-de|emotion|Way of thinking or feeling
|
||||
attractive|at-tra-cti-ve|everyday|Pleasing to look at
|
||||
audience|au-di-en-ce|arts|People watching a performance
|
||||
authority|au-th-or-ity|society|Power to give orders
|
||||
automatic|au-to-ma-tic|tech|Working by itself
|
||||
available|av-ai-la-ble|everyday|Ready to be used
|
||||
background|ba-ck-gro-und|arts|Scenery behind the main subject
|
||||
broadcast|bro-ad-ca-st|tech|Transmit on radio or TV
|
||||
bulletin|bu-ll-et-in|everyday|Short official news update
|
||||
business|bu-si-ne-ss|business|Company or commercial activity
|
||||
calculate|ca-lc-ul-ate|education|Work out with math
|
||||
candidate|can-di-da-te|society|Person running for office
|
||||
capacity|ca-pa-ci-ty|everyday|Maximum amount something can hold
|
||||
category|ca-te-go-ry|everyday|Group of similar things
|
||||
character|ch-ar-ac-ter|arts|Person in a story
|
||||
chemical|ch-em-ic-al|science|Substance made by chemistry
|
||||
collapse|co-ll-ap-se|everyday|Fall down suddenly
|
||||
commercial|com-mer-ci-al|business|TV advertisement
|
||||
committee|com-mi-tt-ee|society|Group chosen to make decisions
|
||||
communicate|com-mu-nic-ate|everyday|Share information
|
||||
community|com-mu-ni-ty|society|People living in one area
|
||||
comparison|com-pa-ri-son|everyday|Looking at similarities and differences
|
||||
complain|co-mp-la-in|emotion|Express unhappiness
|
||||
complaint|co-mp-la-int|everyday|Statement of dissatisfaction
|
||||
complete|co-mp-le-te|everyday|Finished; whole
|
||||
compromise|com-pro-mi-se|society|Deal where both sides give a little
|
||||
conclusion|co-nc-lu-sion|education|The end or final decision
|
||||
concrete|co-nc-re-te|city|Hard building material for sidewalks
|
||||
conference|co-nf-ere-nce|business|Formal meeting for discussion
|
||||
confident|con-fi-de-nt|emotion|Sure of yourself
|
||||
consistent|co-ns-ist-ent|everyday|Unchanging over time
|
||||
constant|co-ns-ta-nt|everyday|Never stopping
|
||||
continue|co-nt-in-ue|everyday|Keep going
|
||||
continuous|con-ti-nu-ous|everyday|Without a break
|
||||
contract|co-nt-ra-ct|business|Written legal agreement
|
||||
contrast|co-nt-ra-st|arts|Striking difference
|
||||
contribute|con-tri-bu-te|society|Give to a shared cause
|
||||
convenient|con-ve-ni-ent|everyday|Easy and handy
|
||||
creature|cr-ea-tu-re|animals|Living animal or being
|
||||
critical|cr-it-ic-al|everyday|Extremely important; faultfinding
|
||||
dangerous|da-ng-er-ous|everyday|Likely to cause harm
|
||||
decision|de-ci-si-on|everyday|A choice that has been made
|
||||
decrease|de-cr-ea-se|everyday|Make smaller
|
||||
dedicate|de-di-ca-te|emotion|Devote to a purpose
|
||||
definite|de-fi-ni-te|everyday|Clearly decided
|
||||
deliberate|de-li-ber-ate|everyday|Done on purpose
|
||||
delivery|de-li-ve-ry|everyday|Bringing goods to the door
|
||||
democratic|de-mo-cra-tic|history|Ruled by the people
|
||||
demonstrate|de-mon-stra-te|education|Show how something works
|
||||
department|de-pa-rt-ment|places|Division of a store or company
|
||||
describe|de-sc-ri-be|words|Tell what something is like
|
||||
desperate|de-sp-er-ate|emotion|Willing to try anything
|
||||
determine|de-ter-mi-ne|everyday|Figure out or decide
|
||||
difference|di-ff-ere-nce|everyday|Way in which things are unlike
|
||||
different|di-ff-er-ent|everyday|Not the same
|
||||
director|di-re-ct-or|arts|Person in charge of making a film
|
||||
disagree|di-sa-gr-ee|everyday|Have a different opinion
|
||||
disappear|di-sa-pp-ear|fantasy|Vanish from sight
|
||||
disaster|di-sa-st-er|nature|Sudden terrible event
|
||||
discount|di-sc-ou-nt|business|Reduction in price
|
||||
discussion|di-sc-us-sion|everyday|Conversation about a topic
|
||||
distance|di-st-an-ce|travel|How far apart things are
|
||||
distinct|di-st-in-ct|everyday|Clearly different
|
||||
district|di-st-ri-ct|city|Area of a city or country
|
||||
division|di-vi-si-on|education|Splitting a number into parts
|
||||
document|do-cu-me-nt|business|Official paper or file
|
||||
economic|ec-on-om-ic|business|Relating to money and trade
|
||||
effective|ef-fe-cti-ve|everyday|Producing the desired result
|
||||
efficient|ef-fi-ci-ent|everyday|Working without waste
|
||||
electric|el-ec-tr-ic|tech|Powered by electricity
|
||||
embarrass|em-ba-rr-ass|emotion|Make someone feel awkward
|
||||
emergency|em-er-gen-cy|health|Serious situation needing quick action
|
||||
emphasis|em-ph-as-is|words|Special importance
|
||||
encounter|en-co-un-ter|everyday|Unexpected meeting
|
||||
encourage|en-cou-ra-ge|emotion|Give support and confidence
|
||||
enormous|en-or-mo-us|everyday|Very large
|
||||
entrance|en-tr-an-ce|places|Way in
|
||||
equipment|equ-ip-me-nt|sports|Tools needed for a job or sport
|
||||
essential|ess-en-ti-al|everyday|Absolutely necessary
|
||||
estimate|es-ti-ma-te|education|Rough calculation
|
||||
excellent|ex-ce-ll-ent|emotion|Extremely good
|
||||
exchange|ex-ch-an-ge|business|Trade one thing for another
|
||||
existence|ex-is-te-nce|mind|State of being real
|
||||
expensive|ex-pen-si-ve|business|Costing a lot
|
||||
expression|ex-pr-es-sion|emotion|Look on someone's face
|
||||
facility|fa-ci-li-ty|places|Building made for a purpose
|
||||
familiar|fa-mi-li-ar|everyday|Well known
|
||||
feedback|fe-ed-ba-ck|business|Comments on how you did
|
||||
financial|fin-an-ci-al|business|Relating to money
|
||||
forthcoming|for-th-com-ing|everyday|About to happen
|
||||
frequent|fr-eq-ue-nt|everyday|Happening often
|
||||
generate|ge-ne-ra-te|tech|Produce or create
|
||||
governor|go-ve-rn-or|history|Elected head of a state
|
||||
graduate|gr-ad-ua-te|education|Finish school
|
||||
grateful|gr-at-ef-ul|emotion|Thankful
|
||||
guarantee|gu-ar-ant-ee|business|Firm promise
|
||||
harmless|ha-rm-le-ss|everyday|Not able to hurt
|
||||
historical|hi-sto-ri-cal|history|Relating to the past
|
||||
immediate|im-me-di-ate|everyday|Happening right away
|
||||
importance|im-por-ta-nce|everyday|State of mattering a lot
|
||||
important|im-po-rt-ant|everyday|Of great value or significance
|
||||
impression|im-pr-es-sion|emotion|Idea formed about someone
|
||||
improvement|im-pro-ve-ment|everyday|Change for the better
|
||||
incident|in-ci-de-nt|everyday|Event or occurrence
|
||||
incomplete|in-com-ple-te|everyday|Not finished
|
||||
increase|in-cr-ea-se|everyday|Make larger
|
||||
indicate|in-di-ca-te|everyday|Point out
|
||||
infinite|in-fi-ni-te|space|Without end
|
||||
influence|in-fl-ue-nce|society|Power to affect others
|
||||
innocent|in-no-ce-nt|emotion|Not guilty
|
||||
instance|in-st-an-ce|everyday|An example
|
||||
insurance|in-su-ra-nce|business|Protection against loss
|
||||
intelligent|in-tel-lig-ent|mind|Smart
|
||||
interact|in-te-ra-ct|society|Act with one another
|
||||
irritate|ir-ri-ta-te|emotion|Annoy
|
||||
language|la-ng-ua-ge|words|System of words people speak
|
||||
lifetime|li-fe-ti-me|everyday|Length of a life
|
||||
majority|ma-jo-ri-ty|society|More than half
|
||||
material|ma-te-ri-al|craft|Fabric or substance things are made of
|
||||
meaningful|me-an-ing-ful|emotion|Full of significance
|
||||
membership|me-mb-ers-hip|society|Belonging to a group
|
||||
military|mi-li-ta-ry|history|Armed forces
|
||||
minority|mi-no-ri-ty|society|Less than half
|
||||
movement|mo-ve-me-nt|everyday|Act of moving
|
||||
national|na-ti-on-al|society|Relating to a nation
|
||||
necessary|nec-es-sa-ry|everyday|Required
|
||||
necessity|ne-ce-ss-ity|everyday|Something you need
|
||||
negative|ne-ga-ti-ve|everyday|Opposite of positive
|
||||
nonsense|no-ns-en-se|words|Silly talk
|
||||
occasion|oc-ca-si-on|everyday|Special event
|
||||
official|of-fi-ci-al|society|Formally approved
|
||||
opposite|op-po-si-te|words|Completely different
|
||||
optional|op-ti-on-al|everyday|Not required
|
||||
ordinary|or-di-na-ry|everyday|Normal; everyday
|
||||
original|or-ig-in-al|arts|The first version
|
||||
paragraph|pa-ra-gra-ph|words|Block of sentences
|
||||
parallel|pa-ra-ll-el|education|Side by side, never meeting
|
||||
particular|par-ti-cu-lar|everyday|Specific; fussy
|
||||
peculiar|pe-cu-li-ar|everyday|Strange or odd
|
||||
performance|per-for-ma-nce|arts|Show in front of an audience
|
||||
permanent|pe-rm-an-ent|everyday|Lasting forever
|
||||
permission|per-mis-si-on|everyday|Being allowed to do something
|
||||
personal|pe-rs-on-al|everyday|Private; your own
|
||||
persuade|pe-rs-ua-de|words|Convince
|
||||
physical|ph-ys-ic-al|health|Relating to the body
|
||||
pleasant|pl-ea-sa-nt|emotion|Nice and enjoyable
|
||||
pointless|po-in-tl-ess|everyday|Having no purpose
|
||||
political|po-li-ti-cal|society|Relating to government
|
||||
positive|po-si-ti-ve|emotion|Hopeful; greater than zero
|
||||
potential|pot-en-ti-al|everyday|Possible future ability
|
||||
powerful|po-we-rf-ul|everyday|Very strong
|
||||
practical|pr-ac-ti-cal|everyday|Useful in real life
|
||||
practice|pr-ac-ti-ce|sports|Repeat to improve
|
||||
preference|pr-ef-ere-nce|everyday|Something liked more
|
||||
presence|pr-es-en-ce|everyday|Being there
|
||||
preserve|pr-es-er-ve|food|Keep safe; fruit jam
|
||||
pressure|pr-es-su-re|science|Force pushing on something
|
||||
previous|pr-ev-io-us|everyday|Coming before
|
||||
principle|pr-in-ci-ple|mind|Basic rule or belief
|
||||
procedure|pr-oc-ed-ure|health|Set way of doing something
|
||||
progress|pr-og-re-ss|everyday|Forward movement
|
||||
property|pr-op-er-ty|home|Land or belongings
|
||||
proposal|pr-op-os-al|emotion|Plan or offer, such as of marriage
|
||||
prospect|pr-os-pe-ct|business|Possibility of future success
|
||||
puncture|pu-nc-tu-re|travel|Small hole, like in a tire
|
||||
quantity|qu-an-ti-ty|everyday|Amount
|
||||
recommend|re-com-me-nd|everyday|Suggest as good
|
||||
register|re-gi-st-er|business|Sign up officially
|
||||
relationship|re-la-tion-ship|emotion|Connection between people
|
||||
relative|re-la-ti-ve|everyday|Family member
|
||||
relevant|re-le-va-nt|everyday|Related to the topic
|
||||
reliable|re-li-ab-le|everyday|Dependable
|
||||
religion|re-li-gi-on|society|Belief system of worship
|
||||
religious|re-li-gi-ous|society|Devoted to a faith
|
||||
reluctant|re-lu-ct-ant|emotion|Unwilling
|
||||
remember|re-me-mb-er|mind|Recall from memory
|
||||
replacement|re-pl-ace-ment|everyday|Thing used instead
|
||||
represent|re-pr-es-ent|society|Stand for or speak for
|
||||
research|re-se-ar-ch|science|Careful study to learn facts
|
||||
resident|re-si-de-nt|home|Person who lives somewhere
|
||||
resource|re-so-ur-ce|everyday|Useful supply
|
||||
response|re-sp-on-se|words|Answer or reply
|
||||
restrict|re-st-ri-ct|everyday|Limit
|
||||
ridiculous|ri-dic-ul-ous|emotion|Absurd
|
||||
secretary|se-cre-ta-ry|jobs|Office assistant
|
||||
security|se-cu-ri-ty|tech|Safety and protection
|
||||
sentence|se-nt-en-ce|words|Group of words expressing a complete thought
|
||||
separate|se-pa-ra-te|everyday|Set apart
|
||||
sequence|se-qu-en-ce|everyday|Order in which things follow
|
||||
shortage|sh-or-ta-ge|business|Not enough of something
|
||||
something|so-me-th-ing|everyday|An unspecified thing
|
||||
southern|so-ut-he-rn|travel|In or from the south
|
||||
standard|st-an-da-rd|everyday|Usual level of quality
|
||||
statement|st-at-em-ent|words|Something said or written formally
|
||||
straight|st-ra-ig-ht|everyday|Without a bend
|
||||
strategy|st-ra-te-gy|games|Plan to reach a goal
|
||||
strength|st-re-ng-th|sports|Being strong
|
||||
substitute|sub-sti-tu-te|sports|Replacement player
|
||||
successful|su-cc-ess-ful|endeavor|Achieving a goal
|
||||
suitable|su-it-ab-le|everyday|Right for the purpose
|
||||
superior|su-pe-ri-or|everyday|Better; higher in rank
|
||||
surprise|su-rp-ri-se|emotion|Unexpected event
|
||||
suspicion|su-spi-ci-on|mystery|Feeling that something is wrong
|
||||
technical|te-ch-ni-cal|tech|Relating to technology or skill
|
||||
technique|te-ch-ni-que|arts|Way of doing something skillfully
|
||||
temporary|te-mp-ora-ry|everyday|Lasting a short time
|
||||
tendency|te-nd-en-cy|mind|Habit or inclination
|
||||
thousand|th-ou-sa-nd|education|Ten hundred
|
||||
together|to-ge-th-er|society|With each other
|
||||
traditional|tra-di-tion-al|history|Following long-held customs
|
||||
translate|tr-an-sl-ate|words|Change into another language
|
||||
transport|tr-an-spo-rt|travel|Carry from place to place
|
||||
treatment|tre-at-me-nt|health|Medical care
|
||||
ultimate|ul-ti-ma-te|everyday|Final; best possible
|
||||
understand|un-der-sta-nd|mind|Grasp the meaning
|
||||
universal|un-iv-ers-al|everyday|Applying to everyone
|
||||
unpleasant|un-ple-as-ant|emotion|Not nice
|
||||
valuable|va-lu-ab-le|everyday|Worth a lot
|
||||
widespread|wi-de-spr-ead|everyday|Found over a large area
|
||||
worthwhile|wor-th-whi-le|everyday|Worth the time or effort
|
||||
`;
|
||||
|
||||
export const extraWords = RAW.trim()
|
||||
|
||||
90
scripts/find-chunk-words.mjs
Normal file
90
scripts/find-chunk-words.mjs
Normal file
@@ -0,0 +1,90 @@
|
||||
// Finds common English words that can be built from exactly 4 existing tiles
|
||||
// (chunks) in the target-word pool, but aren't target words yet.
|
||||
//
|
||||
// Usage: node scripts/find-chunk-words.mjs [--max-tier=35] [--json]
|
||||
import wl from 'wordlist-english';
|
||||
import { DICTIONARY_SET } from '../src/data/lexicon.js';
|
||||
import { TARGET_WORDS_POOL } from '../src/data/puzzles.js';
|
||||
|
||||
const args = Object.fromEntries(process.argv.slice(2).map(a => a.replace(/^--/, '').split('=')));
|
||||
const MAX_TIER = Number(args['max-tier'] || 35);
|
||||
const TIERS = [10, 20, 35, 40, 50].filter(t => t <= MAX_TIER);
|
||||
|
||||
// Every chunk currently used by a target word
|
||||
const chunks = new Set(TARGET_WORDS_POOL.flatMap(w => w.tiles.map(t => t.toLowerCase())));
|
||||
const existing = new Set(TARGET_WORDS_POOL.map(w => w.word));
|
||||
|
||||
// Common words only (frequency tiers from wordlist-english)
|
||||
const candidates = new Set();
|
||||
for (const t of TIERS) for (const w of wl[`english/${t}`] || []) candidates.add(w);
|
||||
|
||||
// Try to split a word into exactly 4 distinct chunks (each >= 2 letters).
|
||||
// Returns the most balanced split, or null.
|
||||
function split(word) {
|
||||
let best = null;
|
||||
const n = word.length;
|
||||
for (let a = 2; a <= n - 6; a++) {
|
||||
const t1 = word.slice(0, a);
|
||||
if (!chunks.has(t1)) continue;
|
||||
for (let b = a + 2; b <= n - 4; b++) {
|
||||
const t2 = word.slice(a, b);
|
||||
if (!chunks.has(t2)) continue;
|
||||
for (let c = b + 2; c <= n - 2; c++) {
|
||||
const t3 = word.slice(b, c);
|
||||
const t4 = word.slice(c);
|
||||
if (!chunks.has(t3) || !chunks.has(t4)) continue;
|
||||
const tiles = [t1, t2, t3, t4];
|
||||
if (new Set(tiles).size !== 4) continue;
|
||||
const lens = tiles.map(t => t.length);
|
||||
const spread = Math.max(...lens) - Math.min(...lens);
|
||||
if (!best || spread < best.spread) best = { tiles, spread };
|
||||
}
|
||||
}
|
||||
}
|
||||
return best && best.tiles;
|
||||
}
|
||||
|
||||
// Skip inflected forms whose base word exists (walked, happier, quickly, kittens...)
|
||||
const allWords = new Set(wl.english);
|
||||
function isInflection(w) {
|
||||
const bases = [];
|
||||
if (w.endsWith('ies')) bases.push(w.slice(0, -3) + 'y');
|
||||
if (w.endsWith('es')) bases.push(w.slice(0, -2));
|
||||
if (w.endsWith('s')) bases.push(w.slice(0, -1));
|
||||
if (w.endsWith('ed')) bases.push(w.slice(0, -2), w.slice(0, -1), w.slice(0, -3));
|
||||
if (w.endsWith('ied')) bases.push(w.slice(0, -3) + 'y');
|
||||
if (w.endsWith('ing')) bases.push(w.slice(0, -3), w.slice(0, -3) + 'e', w.slice(0, -4));
|
||||
if (w.endsWith('ly')) bases.push(w.slice(0, -2), w.slice(0, -3) + 'e');
|
||||
if (w.endsWith('ily')) bases.push(w.slice(0, -3) + 'y');
|
||||
if (w.endsWith('er')) bases.push(w.slice(0, -2), w.slice(0, -1), w.slice(0, -3));
|
||||
if (w.endsWith('est')) bases.push(w.slice(0, -3), w.slice(0, -2), w.slice(0, -4));
|
||||
if (w.endsWith('ness')) bases.push(w.slice(0, -4));
|
||||
return bases.some(b => b.length >= 3 && allWords.has(b));
|
||||
}
|
||||
|
||||
// Skip near-duplicates of words already in the pool (e.g. "dolphin" vs "dolphins")
|
||||
function isInflectionOfExisting(w) {
|
||||
const stems = [w.replace(/s$/, ''), w.replace(/es$/, ''), w.replace(/ies$/, 'y'), w + 's', w + 'es', w.replace(/y$/, 'ies')];
|
||||
return stems.some(s => s !== w && existing.has(s));
|
||||
}
|
||||
|
||||
const found = [];
|
||||
for (const word of candidates) {
|
||||
if (word.length < 8 || word.length > 14) continue;
|
||||
if (!/^[a-z]+$/.test(word)) continue;
|
||||
if (existing.has(word)) continue;
|
||||
if (word.endsWith('tion')) continue;
|
||||
if (!DICTIONARY_SET.has(word)) continue;
|
||||
if (isInflectionOfExisting(word)) continue;
|
||||
if (!('keep-inflections' in args) && isInflection(word)) continue;
|
||||
const tiles = split(word);
|
||||
if (tiles) found.push({ word, tiles });
|
||||
}
|
||||
|
||||
found.sort((a, b) => a.word.localeCompare(b.word));
|
||||
if ('json' in args) {
|
||||
console.log(JSON.stringify(found));
|
||||
} else {
|
||||
for (const f of found) console.log(`${f.word}|${f.tiles.join('-')}`);
|
||||
console.error(`\n${chunks.size} chunks, ${found.length} new words found (tiers <= ${MAX_TIER})`);
|
||||
}
|
||||
68
scripts/lexicon-sources.mjs
Normal file
68
scripts/lexicon-sources.mjs
Normal file
@@ -0,0 +1,68 @@
|
||||
import wordlistEnglish from 'wordlist-english';
|
||||
|
||||
// Shared dictionary sources for the client lexicon and the build-time solver.
|
||||
|
||||
// Valid 2-letter English words accepted in standard games
|
||||
export const VALID_TWO = new Set([
|
||||
'am', 'an', 'as', 'at', 'be', 'by', 'do', 'go', 'he', 'hi',
|
||||
'if', 'in', 'is', 'it', 'me', 'my', 'no', 'of', 'oh', 'on',
|
||||
'or', 'so', 'to', 'up', 'us', 'we'
|
||||
]);
|
||||
|
||||
// The base `english` list excludes regional spellings (neighborhood, color,
|
||||
// theater...), so merge in every regional variant list.
|
||||
const SOURCE_LISTS = [
|
||||
'english',
|
||||
'english/american',
|
||||
'english/british',
|
||||
'english/canadian',
|
||||
'english/australian'
|
||||
];
|
||||
|
||||
// wordlist-english has no proper nouns. Commonly-used proper adjectives and
|
||||
// names that players reasonably expect to be accepted go here.
|
||||
export const PROPER_WORD_ALLOWLIST = [
|
||||
'mediterranean', 'atlantic', 'pacific', 'caribbean', 'arctic', 'antarctic',
|
||||
'european', 'african', 'asian', 'american', 'canadian', 'mexican',
|
||||
'australian', 'arabian', 'egyptian', 'roman', 'greek', 'latin', 'italian',
|
||||
'spanish', 'french', 'english', 'german', 'chinese', 'japanese', 'indian',
|
||||
'olympic', 'olympics', 'christmas', 'easter', 'halloween', 'thanksgiving',
|
||||
'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday',
|
||||
'january', 'february', 'march', 'april', 'may', 'june', 'july', 'august',
|
||||
'september', 'october', 'november', 'december',
|
||||
'mercury', 'venus', 'earth', 'mars', 'jupiter', 'saturn', 'uranus', 'neptune',
|
||||
'amazon', 'sahara', 'everest', 'antarctica', 'africa', 'europe', 'america',
|
||||
'asia', 'australia'
|
||||
];
|
||||
|
||||
function isAcceptable(w) {
|
||||
if (w.length === 2) return VALID_TWO.has(w);
|
||||
return w.length >= 3 && w.length <= 16 && /^[a-z]+$/.test(w);
|
||||
}
|
||||
|
||||
export function buildWordSet() {
|
||||
const set = new Set();
|
||||
for (const key of SOURCE_LISTS) {
|
||||
for (const raw of wordlistEnglish[key] || []) {
|
||||
const w = raw.toLowerCase().trim();
|
||||
if (isAcceptable(w)) set.add(w);
|
||||
}
|
||||
}
|
||||
for (const w of PROPER_WORD_ALLOWLIST) {
|
||||
if (isAcceptable(w)) set.add(w);
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
// Commonness tiers (base + American lists) for word quality ranking
|
||||
const tiers = [10, 20, 35, 50].map(n => new Set([
|
||||
...(wordlistEnglish[`english/${n}`] || []),
|
||||
...(wordlistEnglish[`english/american/${n}`] || [])
|
||||
]));
|
||||
|
||||
export function getCommonnessScore(word) {
|
||||
for (let i = 0; i < tiers.length; i++) {
|
||||
if (tiers[i].has(word)) return 4 - i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1,37 +1,9 @@
|
||||
import fs from 'node:fs';
|
||||
import wordlistEnglish from 'wordlist-english';
|
||||
import { buildWordSet, getCommonnessScore } from './lexicon-sources.mjs';
|
||||
import { capWordList } from '../src/engine/word-cap.js';
|
||||
|
||||
// Valid 2-letter English words accepted in standard games
|
||||
const validTwo = new Set([
|
||||
'am', 'an', 'as', 'at', 'be', 'by', 'do', 'go', 'he', 'hi',
|
||||
'if', 'in', 'is', 'it', 'me', 'my', 'no', 'of', 'oh', 'on',
|
||||
'or', 'so', 'to', 'up', 'us', 'we'
|
||||
]);
|
||||
|
||||
// Build standard clean dictionary (excluding vulgarities, numbers, non-alpha)
|
||||
const cleanWordSet = new Set();
|
||||
for (const raw of wordlistEnglish.english) {
|
||||
const w = raw.toLowerCase().trim();
|
||||
if (w.length === 2 && validTwo.has(w)) {
|
||||
cleanWordSet.add(w);
|
||||
} else if (w.length >= 3 && w.length <= 16 && /^[a-z]+$/.test(w)) {
|
||||
cleanWordSet.add(w);
|
||||
}
|
||||
}
|
||||
|
||||
// Commonness tiers for intelligent word quality ranking
|
||||
const t10 = new Set(wordlistEnglish['english/10'] || []);
|
||||
const t20 = new Set(wordlistEnglish['english/20'] || []);
|
||||
const t35 = new Set(wordlistEnglish['english/35'] || []);
|
||||
const t50 = new Set(wordlistEnglish['english/50'] || []);
|
||||
|
||||
function getCommonnessScore(word) {
|
||||
if (t10.has(word)) return 4;
|
||||
if (t20.has(word)) return 3;
|
||||
if (t35.has(word)) return 2;
|
||||
if (t50.has(word)) return 1;
|
||||
return 0;
|
||||
}
|
||||
// Clean dictionary incl. regional spellings + proper-word allowlist
|
||||
// (same source as src/data/lexicon.js)
|
||||
const cleanWordSet = buildWordSet();
|
||||
|
||||
// Build prefix set for super fast solver pruning (up to 6 letters)
|
||||
const prefixSet = new Set();
|
||||
@@ -117,13 +89,8 @@ export function solveBoard(quartets, maxWords = 30) {
|
||||
return a.word.localeCompare(b.word);
|
||||
});
|
||||
|
||||
// Cap words at maxWords (default: 30). Target quartiles and single-tile words
|
||||
// (tiles that are words on their own) always keep their spot.
|
||||
if (maxWords && words.length > maxWords) {
|
||||
const reserved = words.filter(w => w.isTargetQuartile || w.tileCount === 1);
|
||||
const rest = words.filter(w => !w.isTargetQuartile && w.tileCount !== 1);
|
||||
words = [...reserved, ...rest.slice(0, Math.max(0, maxWords - reserved.length))];
|
||||
}
|
||||
// Cap words at maxWords (default: 30) while keeping a fair share of 2-tile words.
|
||||
words = capWordList(words, maxWords);
|
||||
|
||||
// Final display sorting: Target quartiles first, then points desc, then alphabetical
|
||||
words.sort((a, b) => {
|
||||
|
||||
Reference in New Issue
Block a user