init
This commit is contained in:
323
scripts/build-all-data.mjs
Normal file
323
scripts/build-all-data.mjs
Normal file
@@ -0,0 +1,323 @@
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import wordlistEnglish from 'wordlist-english';
|
||||
import { solveBoard } from './solver.mjs';
|
||||
|
||||
const targetWordsPool = [
|
||||
// Wonder & Exploration
|
||||
{ word: 'remarkable', tiles: ['re', 'mar', 'ka', 'ble'], theme: 'wonder', clue: 'Worthy of attention; striking' },
|
||||
{ word: 'unforgettable', tiles: ['un', 'for', 'get', 'table'], theme: 'wonder', clue: 'Impossible to forget; memorable' },
|
||||
{ word: 'photography', tiles: ['pho', 'to', 'gra', 'phy'], theme: 'wonder', clue: 'The art or practice of taking photos' },
|
||||
{ word: 'adventurous', tiles: ['ad', 'ven', 'tur', 'ous'], theme: 'wonder', clue: 'Willing to take risks or try new things' },
|
||||
{ word: 'inspiration', tiles: ['in', 'spi', 'ra', 'tion'], theme: 'wonder', clue: 'A stimulus to creative thought or action' },
|
||||
|
||||
// Space & Cosmos
|
||||
{ word: 'astronomy', tiles: ['as', 'tro', 'no', 'my'], theme: 'space', clue: 'The branch of science dealing with space' },
|
||||
{ word: 'gravitation', tiles: ['gra', 'vi', 'ta', 'tion'], theme: 'space', clue: 'The force that attracts bodies toward mass' },
|
||||
{ word: 'atmosphere', tiles: ['at', 'mo', 'sph', 'ere'], theme: 'space', clue: 'The envelope of gases surrounding a planet' },
|
||||
{ word: 'interstellar', tiles: ['in', 'ter', 'ste', 'llar'], theme: 'space', clue: 'Occurring between stars' },
|
||||
{ word: 'telescopic', tiles: ['tel', 'es', 'co', 'pic'], theme: 'space', clue: 'Having the power for viewing distant objects' },
|
||||
|
||||
// Science & Discovery
|
||||
{ word: 'required', tiles: ['re', 'qu', 'ir', 'ed'], theme: 'science', clue: 'Officially compulsory or needed' },
|
||||
{ word: 'equivalent', tiles: ['equ', 'iv', 'al', 'ent'], theme: 'science', clue: 'Equal in value, amount, or meaning' },
|
||||
{ word: 'objection', tiles: ['obj', 'ec', 'ti', 'on'], theme: 'science', clue: 'An expression or feeling of disapproval' },
|
||||
{ word: 'justification', tiles: ['ju', 'stif', 'ica', 'tion'], theme: 'science', clue: 'The action of showing something to be right' },
|
||||
{ word: 'mysterious', tiles: ['mys', 'ter', 'io', 'us'], theme: 'science', clue: 'Difficult or impossible to understand' },
|
||||
|
||||
// Nature & Earth
|
||||
{ word: 'biodiversity', tiles: ['bio', 'di', 'ver', 'sity'], theme: 'nature', clue: 'The variety of life in the world or habitat' },
|
||||
{ word: 'environment', tiles: ['en', 'vi', 'ron', 'ment'], theme: 'nature', clue: 'The surroundings or conditions in which one lives' },
|
||||
{ word: 'caterpillar', tiles: ['cat', 'er', 'pil', 'lar'], theme: 'nature', clue: 'The larval stage of a butterfly or moth' },
|
||||
{ word: 'underwater', tiles: ['un', 'der', 'wa', 'ter'], theme: 'nature', clue: 'Situated or occurring below water surface' },
|
||||
{ word: 'thunderstorm', tiles: ['thun', 'der', 'sto', 'rm'], theme: 'nature', clue: 'A transient storm of lightning and thunder' },
|
||||
|
||||
// Mind & Philosophy
|
||||
{ word: 'imagination', tiles: ['im', 'agi', 'na', 'tion'], theme: 'mind', clue: 'The faculty of forming new ideas or images' },
|
||||
{ word: 'understanding', tiles: ['un', 'der', 'stan', 'ding'], theme: 'mind', clue: 'The ability to comprehend something' },
|
||||
{ word: 'psychology', tiles: ['psy', 'cho', 'lo', 'gy'], theme: 'mind', clue: 'The scientific study of mind and behavior' },
|
||||
{ word: 'intelligence', tiles: ['in', 'tel', 'li', 'gence'], theme: 'mind', clue: 'The ability to acquire and apply knowledge' },
|
||||
{ word: 'consciousness', tiles: ['con', 'sci', 'ous', 'ness'], theme: 'mind', clue: 'The state of being aware of one surroundings' },
|
||||
|
||||
// Architecture & City
|
||||
{ word: 'architecture', tiles: ['ar', 'chi', 'tec', 'ture'], theme: 'city', clue: 'The art and practice of designing buildings' },
|
||||
{ word: 'metropolitan', tiles: ['me', 'tro', 'pol', 'itan'], theme: 'city', clue: 'Relating to a large, busy city' },
|
||||
{ word: 'construction', tiles: ['con', 'stru', 'cti', 'on'], theme: 'city', clue: 'The building of something typically large' },
|
||||
{ word: 'neighborhood', tiles: ['neigh', 'bor', 'ho', 'od'], theme: 'city', clue: 'A district or area forming a community' },
|
||||
{ word: 'skyscraper', tiles: ['sky', 'sc', 'ra', 'per'], theme: 'city', clue: 'A very tall building with many stories' },
|
||||
|
||||
// Music & Arts
|
||||
{ word: 'symphony', tiles: ['sym', 'pho', 'ni', 'cally'], theme: 'arts', clue: 'Relating to an elaborate musical composition' },
|
||||
{ word: 'masterpiece', tiles: ['mas', 'ter', 'pie', 'ce'], theme: 'arts', clue: 'A work of outstanding artistry or skill' },
|
||||
{ word: 'performance', tiles: ['per', 'for', 'man', 'ce'], theme: 'arts', clue: 'An act of staging or presenting a play or concert' },
|
||||
{ word: 'exhibition', tiles: ['ex', 'hi', 'bi', 'tion'], theme: 'arts', clue: 'A public display of works of art or items' },
|
||||
{ word: 'creativity', tiles: ['cre', 'at', 'iv', 'ity'], theme: 'arts', clue: 'The use of the imagination or original ideas' },
|
||||
|
||||
// Technology & Future
|
||||
{ word: 'technology', tiles: ['tec', 'hno', 'lo', 'gy'], theme: 'tech', clue: 'Application of scientific knowledge for practical aims' },
|
||||
{ word: 'electronic', tiles: ['el', 'ect', 'ro', 'nic'], theme: 'tech', clue: 'Having components like microchips or transistors' },
|
||||
{ word: 'automation', tiles: ['au', 'to', 'ma', 'tion'], theme: 'tech', clue: 'The use of largely automatic equipment in a system' },
|
||||
{ word: 'innovation', tiles: ['in', 'no', 'va', 'tion'], theme: 'tech', clue: 'A new method, idea, or product' },
|
||||
{ word: 'computation', tiles: ['com', 'pu', 'ta', 'tion'], theme: 'tech', clue: 'The action of mathematical calculation' },
|
||||
|
||||
// Society & Community
|
||||
{ word: 'celebration', tiles: ['cel', 'eb', 'ra', 'tion'], theme: 'society', clue: 'The action of marking one pleasure at an event' },
|
||||
{ word: 'communication', tiles: ['com', 'mu', 'ni', 'cation'], theme: 'society', clue: 'The imparting or exchanging of information' },
|
||||
{ word: 'relationship', tiles: ['re', 'la', 'tion', 'ship'], theme: 'society', clue: 'The way in which two or more concepts or people connect' },
|
||||
{ word: 'opportunity', tiles: ['op', 'por', 'tu', 'nity'], theme: 'society', clue: 'A set of circumstances making it possible to do something' },
|
||||
{ word: 'conversation', tiles: ['con', 'ver', 'sa', 'tion'], theme: 'society', clue: 'A talk between two or more people' },
|
||||
|
||||
// Literature & Words
|
||||
{ word: 'vocabulary', tiles: ['vo', 'cab', 'ul', 'ary'], theme: 'words', clue: 'The body of words used in a particular language' },
|
||||
{ word: 'encyclopedia', tiles: ['en', 'cy', 'clo', 'pedia'], theme: 'words', clue: 'A book or set providing information on many subjects' },
|
||||
{ word: 'dictionary', tiles: ['dic', 'tion', 'ar', 'y'], theme: 'words', clue: 'A reference book on words and definitions' },
|
||||
{ word: 'manuscript', tiles: ['man', 'us', 'cr', 'ipt'], theme: 'words', clue: 'An author text that has not yet been printed' },
|
||||
{ word: 'translation', tiles: ['trans', 'la', 'ti', 'on'], theme: 'words', clue: 'The process of translating words into another language' },
|
||||
|
||||
// Travel & Geography
|
||||
{ word: 'destination', tiles: ['des', 'ti', 'na', 'tion'], theme: 'travel', clue: 'The place to which someone is going or being sent' },
|
||||
{ word: 'navigation', tiles: ['na', 'vi', 'ga', 'tion'], theme: 'travel', clue: 'The process of accurately ascertaining one position' },
|
||||
{ word: 'continental', tiles: ['con', 'ti', 'nen', 'tal'], theme: 'travel', clue: 'Forming or belonging to a continent' },
|
||||
{ word: 'expedition', tiles: ['ex', 'pe', 'di', 'tion'], theme: 'travel', clue: 'A journey undertaken by a group with a definite purpose' },
|
||||
{ word: 'exploration', tiles: ['ex', 'plo', 'ra', 'tion'], theme: 'travel', clue: 'The action of traveling in or through an unfamiliar area' },
|
||||
|
||||
// Seasons & Weather
|
||||
{ word: 'temperatures', tiles: ['tem', 'per', 'at', 'ures'], theme: 'weather', clue: 'The degrees or intensities of heat present in an area' },
|
||||
{ word: 'precipitation', tiles: ['pre', 'cip', 'ita', 'tion'], theme: 'weather', clue: 'Rain, snow, sleet, or hail that falls to the ground' },
|
||||
{ word: 'meteorology', tiles: ['me', 'teo', 'rol', 'ogy'], theme: 'weather', clue: 'The science concerned with processes of the atmosphere' },
|
||||
{ word: 'hibernation', tiles: ['hi', 'ber', 'na', 'tion'], theme: 'weather', clue: 'The condition or period of an animal spending winter asleep' },
|
||||
{ word: 'illumination', tiles: ['il', 'lum', 'ina', 'tion'], theme: 'weather', clue: 'Lighting or light provided' },
|
||||
|
||||
// Botany & Garden
|
||||
{ word: 'photosynthesis', tiles: ['pho', 'to', 'syn', 'thesis'], theme: 'plants', clue: 'Process by which green plants synthesize nutrients' },
|
||||
{ word: 'chlorophyll', tiles: ['chl', 'oro', 'ph', 'yll'], theme: 'plants', clue: 'A green pigment responsible for light absorption in plants' },
|
||||
{ word: 'horticulture', tiles: ['hor', 'ti', 'cul', 'ture'], theme: 'plants', clue: 'The art or practice of garden cultivation' },
|
||||
{ word: 'germination', tiles: ['ger', 'mi', 'na', 'tion'], theme: 'plants', clue: 'The development of a plant from a seed or spore' },
|
||||
{ word: 'cultivation', tiles: ['cul', 'ti', 'va', 'tion'], theme: 'plants', clue: 'The act of caring for and encouraging plant growth' },
|
||||
|
||||
// Wisdom & Knowledge
|
||||
{ word: 'extraordinary', tiles: ['ex', 'tra', 'ordi', 'nary'], theme: 'wisdom', clue: 'Very unusual or remarkable' },
|
||||
{ word: 'satisfaction', tiles: ['sa', 'tis', 'fac', 'tion'], theme: 'wisdom', clue: 'Fulfillment of one wishes or expectations' },
|
||||
{ word: 'anticipation', tiles: ['an', 'ti', 'cip', 'ation'], theme: 'wisdom', clue: 'The act of expecting something in advance' },
|
||||
{ word: 'consideration', tiles: ['con', 'sid', 'era', 'tion'], theme: 'wisdom', clue: 'Careful thought over a period of time' },
|
||||
{ word: 'investigation', tiles: ['in', 'ves', 'ti', 'gation'], theme: 'wisdom', clue: 'A formal inquiry or systematic examination' },
|
||||
|
||||
// Ocean & Marine
|
||||
{ word: 'oceanography', tiles: ['oce', 'ano', 'gra', 'phy'], theme: 'ocean', clue: 'The branch of science that deals with physical oceans' },
|
||||
{ word: 'submersible', tiles: ['sub', 'mer', 'si', 'ble'], theme: 'ocean', clue: 'Designed to operate completely underwater' },
|
||||
{ word: 'navigation', tiles: ['na', 'vi', 'ga', 'tion'], theme: 'ocean', clue: 'Planning and directing route of ship or craft' },
|
||||
{ word: 'constellation', tiles: ['con', 'ste', 'lla', 'tion'], theme: 'ocean', clue: 'A group of stars forming a recognizable pattern' },
|
||||
{ word: 'mediterranean', tiles: ['med', 'ite', 'rra', 'nean'], theme: 'ocean', clue: 'Of or characteristic of the Mediterranean Sea' },
|
||||
|
||||
// Human Endeavor
|
||||
{ word: 'determination', tiles: ['de', 'ter', 'mi', 'nation'], theme: 'endeavor', clue: 'Firmness of purpose; resoluteness' },
|
||||
{ word: 'perseverance', tiles: ['per', 'sev', 'er', 'ance'], theme: 'endeavor', clue: 'Persistence in doing something despite difficulty' },
|
||||
{ word: 'accomplished', tiles: ['ac', 'com', 'pli', 'shed'], theme: 'endeavor', clue: 'Highly trained or skilled in a field' },
|
||||
{ word: 'achievement', tiles: ['ach', 'ie', 've', 'ment'], theme: 'endeavor', clue: 'A thing done successfully with effort' },
|
||||
{ word: 'distinguished', tiles: ['dis', 'tin', 'gui', 'shed'], theme: 'endeavor', clue: 'Successful, well known, and respected' },
|
||||
|
||||
// Energy & Physics
|
||||
{ word: 'electricity', tiles: ['el', 'ect', 'ri', 'city'], theme: 'physics', clue: 'Form of energy from charged elementary particles' },
|
||||
{ word: 'acceleration', tiles: ['ac', 'cel', 'era', 'tion'], theme: 'physics', clue: 'The rate of change of velocity per unit time' },
|
||||
{ word: 'thermodynamic', tiles: ['the', 'rmo', 'dyn', 'amic'], theme: 'physics', clue: 'Relating to heat and its relation to work and energy' },
|
||||
{ word: 'equilibrium', tiles: ['equ', 'ili', 'bri', 'um'], theme: 'physics', clue: 'A state in which opposing forces are balanced' },
|
||||
{ word: 'radioactivity', tiles: ['rad', 'ioa', 'cti', 'vity'], theme: 'physics', clue: 'The emission of ionizing radiation from nuclei' }
|
||||
];
|
||||
|
||||
console.log('Target words pool size:', targetWordsPool.length);
|
||||
|
||||
// Generate 30 curated daily and themed puzzles
|
||||
const dailyPuzzlesDefs = [
|
||||
{
|
||||
id: '2026-10-23',
|
||||
date: '2026-10-23',
|
||||
title: 'Daily Puzzle — Oct 23, 2026',
|
||||
theme: 'Discovery & Wonder',
|
||||
difficulty: 'Normal',
|
||||
words: ['remarkable', 'unforgettable', 'photography', 'adventurous', 'inspiration']
|
||||
},
|
||||
{
|
||||
id: '2026-10-24',
|
||||
date: '2026-10-24',
|
||||
title: 'Daily Puzzle — Oct 24, 2026',
|
||||
theme: 'Cosmic Horizons',
|
||||
difficulty: 'Challenging',
|
||||
words: ['astronomy', 'gravitation', 'atmosphere', 'interstellar', 'telescopic']
|
||||
},
|
||||
{
|
||||
id: '2026-10-25',
|
||||
date: '2026-10-25',
|
||||
title: 'Daily Puzzle — Oct 25, 2026',
|
||||
theme: 'Mind & Memory',
|
||||
difficulty: 'Normal',
|
||||
words: ['imagination', 'understanding', 'psychology', 'intelligence', 'consciousness']
|
||||
},
|
||||
{
|
||||
id: '2026-10-26',
|
||||
date: '2026-10-26',
|
||||
title: 'Daily Puzzle — Oct 26, 2026',
|
||||
theme: 'Urban Pulse',
|
||||
difficulty: 'Challenging',
|
||||
words: ['architecture', 'metropolitan', 'construction', 'neighborhood', 'skyscraper']
|
||||
},
|
||||
{
|
||||
id: '2026-10-27',
|
||||
date: '2026-10-27',
|
||||
title: 'Daily Puzzle — Oct 27, 2026',
|
||||
theme: 'Harmony & Arts',
|
||||
difficulty: 'Normal',
|
||||
words: ['symphony', 'masterpiece', 'performance', 'exhibition', 'creativity']
|
||||
},
|
||||
{
|
||||
id: '2026-10-28',
|
||||
date: '2026-10-28',
|
||||
title: 'Daily Puzzle — Oct 28, 2026',
|
||||
theme: 'Digital Future',
|
||||
difficulty: 'Normal',
|
||||
words: ['technology', 'electronic', 'automation', 'innovation', 'computation']
|
||||
},
|
||||
{
|
||||
id: '2026-10-29',
|
||||
date: '2026-10-29',
|
||||
title: 'Daily Puzzle — Oct 29, 2026',
|
||||
theme: 'Celebrations',
|
||||
difficulty: 'Easy',
|
||||
words: ['celebration', 'communication', 'relationship', 'opportunity', 'conversation']
|
||||
},
|
||||
{
|
||||
id: '2026-10-30',
|
||||
date: '2026-10-30',
|
||||
title: 'Daily Puzzle — Oct 30, 2026',
|
||||
theme: 'Wild Kingdom',
|
||||
difficulty: 'Normal',
|
||||
words: ['biodiversity', 'environment', 'caterpillar', 'underwater', 'thunderstorm']
|
||||
},
|
||||
{
|
||||
id: '2026-10-31',
|
||||
date: '2026-10-31',
|
||||
title: 'Daily Puzzle — Oct 31, 2026',
|
||||
theme: 'Mysteries & Legends',
|
||||
difficulty: 'Challenging',
|
||||
words: ['mysterious', 'determination', 'perseverance', 'investigation', 'anticipation']
|
||||
},
|
||||
{
|
||||
id: '2026-10-22',
|
||||
date: '2026-10-22',
|
||||
title: 'Daily Puzzle — Oct 22, 2026',
|
||||
theme: 'Scientific Insight',
|
||||
difficulty: 'Normal',
|
||||
words: ['required', 'equivalent', 'objection', 'justification', 'mysterious']
|
||||
},
|
||||
{
|
||||
id: '2026-10-21',
|
||||
date: '2026-10-21',
|
||||
title: 'Daily Puzzle — Oct 21, 2026',
|
||||
theme: 'Wordsmith Almanac',
|
||||
difficulty: 'Normal',
|
||||
words: ['vocabulary', 'encyclopedia', 'dictionary', 'manuscript', 'translation']
|
||||
},
|
||||
{
|
||||
id: '2026-10-20',
|
||||
date: '2026-10-20',
|
||||
title: 'Daily Puzzle — Oct 20, 2026',
|
||||
theme: 'Globe Trekker',
|
||||
difficulty: 'Normal',
|
||||
words: ['destination', 'navigation', 'continental', 'expedition', 'exploration']
|
||||
},
|
||||
{
|
||||
id: '2026-10-19',
|
||||
date: '2026-10-19',
|
||||
title: 'Daily Puzzle — Oct 19, 2026',
|
||||
theme: 'Atmospheric Skies',
|
||||
difficulty: 'Challenging',
|
||||
words: ['temperatures', 'precipitation', 'meteorology', 'hibernation', 'illumination']
|
||||
},
|
||||
{
|
||||
id: '2026-10-18',
|
||||
date: '2026-10-18',
|
||||
title: 'Daily Puzzle — Oct 18, 2026',
|
||||
theme: 'Green Oasis',
|
||||
difficulty: 'Normal',
|
||||
words: ['photosynthesis', 'chlorophyll', 'horticulture', 'germination', 'cultivation']
|
||||
},
|
||||
{
|
||||
id: '2026-10-17',
|
||||
date: '2026-10-17',
|
||||
title: 'Daily Puzzle — Oct 17, 2026',
|
||||
theme: 'Grit & Glory',
|
||||
difficulty: 'Normal',
|
||||
words: ['determination', 'perseverance', 'accomplished', 'achievement', 'distinguished']
|
||||
},
|
||||
{
|
||||
id: '2026-10-16',
|
||||
date: '2026-10-16',
|
||||
title: 'Daily Puzzle — Oct 16, 2026',
|
||||
theme: 'Oceanic Depths',
|
||||
difficulty: 'Challenging',
|
||||
words: ['oceanography', 'submersible', 'constellation', 'mediterranean', 'exploration']
|
||||
},
|
||||
{
|
||||
id: '2026-10-15',
|
||||
date: '2026-10-15',
|
||||
title: 'Daily Puzzle — Oct 15, 2026',
|
||||
theme: 'Energy & Waves',
|
||||
difficulty: 'Expert',
|
||||
words: ['electricity', 'acceleration', 'thermodynamic', 'equilibrium', 'radioactivity']
|
||||
}
|
||||
];
|
||||
|
||||
// Map target words for quick lookup
|
||||
const wordMap = new Map();
|
||||
for (const item of targetWordsPool) {
|
||||
wordMap.set(item.word, item);
|
||||
}
|
||||
|
||||
const solvedPuzzles = [];
|
||||
|
||||
for (const def of dailyPuzzlesDefs) {
|
||||
const quartets = def.words.map(w => {
|
||||
const found = wordMap.get(w);
|
||||
if (!found) throw new Error('Missing word in pool: ' + w);
|
||||
return found.tiles;
|
||||
});
|
||||
|
||||
const solved = solveBoard(quartets);
|
||||
|
||||
// Add clues to target quartiles
|
||||
const quartileDetails = def.words.map(w => {
|
||||
const item = wordMap.get(w);
|
||||
return {
|
||||
word: item.word,
|
||||
tiles: item.tiles,
|
||||
clue: item.clue
|
||||
};
|
||||
});
|
||||
|
||||
solvedPuzzles.push({
|
||||
id: def.id,
|
||||
date: def.date,
|
||||
title: def.title,
|
||||
theme: def.theme,
|
||||
difficulty: def.difficulty,
|
||||
quartets,
|
||||
tiles: solved.tiles,
|
||||
targetQuartiles: solved.targetQuartiles,
|
||||
quartileDetails,
|
||||
words: solved.words,
|
||||
wordCount: solved.wordCount,
|
||||
maxPossibleScore: solved.maxPossibleScore
|
||||
});
|
||||
|
||||
console.log(`Generated: ${def.id} [${def.theme}] -> ${solved.wordCount} words, max score: ${solved.maxPossibleScore}`);
|
||||
}
|
||||
|
||||
// Write solved puzzles to src/data/puzzles.js
|
||||
const puzzlesFileContent = `// Pre-computed solved daily and themed puzzles for Quartiles
|
||||
export const CURATED_PUZZLES = ${JSON.stringify(solvedPuzzles, null, 2)};
|
||||
|
||||
export const TARGET_WORDS_POOL = ${JSON.stringify(targetWordsPool, null, 2)};
|
||||
`;
|
||||
|
||||
fs.mkdirSync('src/data', { recursive: true });
|
||||
fs.writeFileSync('src/data/puzzles.js', puzzlesFileContent, 'utf8');
|
||||
console.log('Saved src/data/puzzles.js successfully!');
|
||||
45
scripts/build-client-lexicon.mjs
Normal file
45
scripts/build-client-lexicon.mjs
Normal file
@@ -0,0 +1,45 @@
|
||||
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'
|
||||
]);
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Total vocabulary words:', vocabulary.size);
|
||||
|
||||
// Pack into space-separated string or array
|
||||
const sortedWords = [...vocabulary].sort();
|
||||
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);
|
||||
|
||||
// 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());
|
||||
}
|
||||
`;
|
||||
|
||||
fs.writeFileSync('src/data/lexicon.js', lexiconContent, 'utf8');
|
||||
console.log('Saved src/data/lexicon.js successfully!');
|
||||
108
scripts/solver.mjs
Normal file
108
scripts/solver.mjs
Normal file
@@ -0,0 +1,108 @@
|
||||
import fs from 'node:fs';
|
||||
import wordlistEnglish from 'wordlist-english';
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
// Build prefix set for super fast solver pruning (up to 6 letters)
|
||||
const prefixSet = new Set();
|
||||
for (const word of cleanWordSet) {
|
||||
for (let len = 1; len <= Math.min(word.length, 6); len++) {
|
||||
prefixSet.add(word.slice(0, len));
|
||||
}
|
||||
}
|
||||
|
||||
// Function to solve a 20-tile board and return all valid words and paths
|
||||
export function solveBoard(quartets) {
|
||||
const tiles = quartets.flat();
|
||||
const foundMap = new Map();
|
||||
|
||||
function search(prefix, usedIndices) {
|
||||
if (prefix.length > 0) {
|
||||
const checkLen = Math.min(prefix.length, 6);
|
||||
if (!prefixSet.has(prefix.slice(0, checkLen))) return;
|
||||
}
|
||||
|
||||
if (prefix.length >= 2 && cleanWordSet.has(prefix)) {
|
||||
if (!foundMap.has(prefix)) {
|
||||
foundMap.set(prefix, [...usedIndices]);
|
||||
}
|
||||
}
|
||||
if (usedIndices.length >= 4) return;
|
||||
|
||||
for (let i = 0; i < tiles.length; i++) {
|
||||
if (usedIndices.includes(i)) continue;
|
||||
usedIndices.push(i);
|
||||
search(prefix + tiles[i], usedIndices);
|
||||
usedIndices.pop();
|
||||
}
|
||||
}
|
||||
|
||||
search('', []);
|
||||
|
||||
const quartilesList = quartets.map(q => q.join(''));
|
||||
const quartileSet = new Set(quartilesList);
|
||||
|
||||
const words = [];
|
||||
let totalScore = 0;
|
||||
let quartileCount = 0;
|
||||
|
||||
for (const [word, path] of foundMap.entries()) {
|
||||
const tileSegments = path.map(idx => tiles[idx]);
|
||||
const tileCount = path.length;
|
||||
let points = tileCount === 4 ? 8 : tileCount === 3 ? 4 : tileCount;
|
||||
const isTargetQuartile = quartileSet.has(word);
|
||||
const isQuartile = tileCount === 4;
|
||||
|
||||
if (isQuartile) quartileCount++;
|
||||
totalScore += points;
|
||||
|
||||
words.push({
|
||||
word,
|
||||
points,
|
||||
tileCount,
|
||||
tileIndices: path,
|
||||
tileSegments,
|
||||
isTargetQuartile,
|
||||
isQuartile
|
||||
});
|
||||
}
|
||||
|
||||
// Add 40 bonus points for finding all 5 quartiles
|
||||
const maxPossibleScore = totalScore + 40;
|
||||
|
||||
// Sort words: Quartiles first, then by points descending, then alphabetically
|
||||
words.sort((a, b) => {
|
||||
if (a.isTargetQuartile !== b.isTargetQuartile) return a.isTargetQuartile ? -1 : 1;
|
||||
if (b.points !== a.points) return b.points - a.points;
|
||||
return a.word.localeCompare(b.word);
|
||||
});
|
||||
|
||||
return {
|
||||
tiles,
|
||||
quartets,
|
||||
targetQuartiles: quartilesList,
|
||||
words,
|
||||
wordCount: words.length,
|
||||
quartileCount: 5,
|
||||
totalBaseScore: totalScore,
|
||||
maxPossibleScore
|
||||
};
|
||||
}
|
||||
|
||||
console.log('Solver module ready. Clean words count:', cleanWordSet.size);
|
||||
Reference in New Issue
Block a user