more words
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import wordlistEnglish from 'wordlist-english';
|
||||
import { solveBoard } from './solver.mjs';
|
||||
import { extraWords } from './extra-words.mjs';
|
||||
import { DICTIONARY_SET } from '../src/data/lexicon.js';
|
||||
|
||||
const targetWordsPool = [
|
||||
export 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' },
|
||||
@@ -17,27 +18,18 @@ const targetWordsPool = [
|
||||
{ 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' },
|
||||
{ word: 'constellation', tiles: ['con', 'ste', 'lla', 'tion'], theme: 'space', clue: 'A group of stars forming a pattern' },
|
||||
{ word: 'stratosphere', tiles: ['stra', 'tos', 'phe', 're'], theme: 'space', clue: 'Layer of the atmosphere above troposphere' },
|
||||
{ word: 'superconductor', tiles: ['su', 'per', 'con', 'ductor'], theme: 'space', clue: 'Material with zero electrical resistance' },
|
||||
|
||||
// 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' },
|
||||
{ word: 'consciousness', tiles: ['con', 'sci', 'ous', 'ness'], theme: 'mind', clue: 'The state of being aware of surroundings' },
|
||||
{ word: 'philosophy', tiles: ['phi', 'los', 'op', 'hy'], theme: 'mind', clue: 'The study of fundamental nature of knowledge' },
|
||||
{ word: 'thoughtfulness', tiles: ['thou', 'ght', 'ful', 'ness'], theme: 'mind', clue: 'The state of thinking deeply or being caring' },
|
||||
|
||||
// Architecture & City
|
||||
{ word: 'architecture', tiles: ['ar', 'chi', 'tec', 'ture'], theme: 'city', clue: 'The art and practice of designing buildings' },
|
||||
@@ -47,86 +39,224 @@ const targetWordsPool = [
|
||||
{ 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: 'symphonically', 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: 'calligraphy', tiles: ['cal', 'lig', 'ra', 'phy'], theme: 'arts', clue: 'Decorative handwriting or handwritten lettering' },
|
||||
{ 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' },
|
||||
{ word: 'choreography', tiles: ['cho', 'reo', 'gra', 'phy'], theme: 'arts', clue: 'The sequence of steps and movements in dance' },
|
||||
{ word: 'harmonium', tiles: ['har', 'mo', 'ni', 'um'], theme: 'arts', clue: 'A keyboard instrument like an organ' },
|
||||
|
||||
// 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' },
|
||||
{ word: 'semiconductor', tiles: ['sem', 'ico', 'ndu', 'ctor'], theme: 'tech', clue: 'Solid substance conducting electricity between conductor and insulator' },
|
||||
{ word: 'cybersecurity', tiles: ['cy', 'ber', 'sec', 'urity'], theme: 'tech', clue: 'Protection of computer systems from attack or theft' },
|
||||
{ word: 'microprocessor', tiles: ['mi', 'cro', 'pro', 'cessor'], theme: 'tech', clue: 'An integrated circuit containing CPU' },
|
||||
{ word: 'motherboard', tiles: ['mo', 'ther', 'bo', 'ard'], theme: 'tech', clue: 'A printed circuit board containing principal components' },
|
||||
|
||||
// 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' },
|
||||
// Celebrations & Community
|
||||
{ word: 'celebration', tiles: ['cel', 'eb', 'ra', 'tion'], theme: 'society', clue: 'The action of marking pleasure at an event' },
|
||||
{ word: 'fellowship', tiles: ['fel', 'low', 'sh', 'ip'], theme: 'society', clue: 'Friendly association, especially with shared interests' },
|
||||
{ word: 'generosity', tiles: ['gen', 'ero', 'si', 'ty'], theme: 'society', clue: 'The quality of being kind and generous' },
|
||||
{ word: 'opportunity', tiles: ['op', 'por', 'tu', 'nity'], theme: 'society', clue: 'A set of circumstances making something possible' },
|
||||
{ word: 'marshmallow', tiles: ['mar', 'shm', 'all', 'ow'], theme: 'society', clue: 'A sweet chewy confection made of sugar and gelatin' },
|
||||
{ word: 'hospitality', tiles: ['hos', 'pit', 'al', 'ity'], theme: 'society', clue: 'Friendly and generous reception of guests' },
|
||||
{ word: 'friendship', tiles: ['fri', 'end', 'sh', 'ip'], theme: 'society', clue: 'A state of mutual trust and support between 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' },
|
||||
// Nature & Wild Kingdom
|
||||
{ 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: 'wilderness', tiles: ['wil', 'der', 'ne', 'ss'], theme: 'nature', clue: 'An uncultivated, uninhabited, and hospitable region' },
|
||||
{ word: 'chameleon', tiles: ['cha', 'me', 'le', 'on'], theme: 'nature', clue: 'A lizard capable of changing skin color' },
|
||||
{ word: 'hummingbird', tiles: ['hum', 'ming', 'bi', 'rd'], theme: 'nature', clue: 'Small nectar-feeding bird with hovering flight' },
|
||||
{ word: 'woodpecker', tiles: ['wood', 'pe', 'ck', 'er'], theme: 'nature', clue: 'A bird with a strong beak for drilling into wood' },
|
||||
{ word: 'butterflies', tiles: ['but', 'ter', 'fli', 'es'], theme: 'nature', clue: 'Insects with large, often brightly colored wings' },
|
||||
{ word: 'grasshoppers', tiles: ['grass', 'hop', 'pe', 'rs'], theme: 'nature', clue: 'Plant-eating insect with powerful hind legs for jumping' },
|
||||
|
||||
// Mysteries & Legends
|
||||
{ word: 'mysterious', tiles: ['mys', 'ter', 'io', 'us'], theme: 'mystery', clue: 'Difficult or impossible to understand or explain' },
|
||||
{ word: 'supernatural', tiles: ['su', 'per', 'nat', 'ural'], theme: 'mystery', clue: 'Attributed to some force beyond scientific understanding' },
|
||||
{ word: 'apparition', tiles: ['ap', 'par', 'it', 'ion'], theme: 'mystery', clue: 'A ghost or ghostlike image of a person' },
|
||||
{ word: 'enchanted', tiles: ['en', 'cha', 'nt', 'ed'], theme: 'mystery', clue: 'Placed under a spell; bewitched' },
|
||||
{ word: 'miraculous', tiles: ['mi', 'rac', 'ul', 'ous'], theme: 'mystery', clue: 'Occurring through divine or extraordinary intervention' },
|
||||
|
||||
// Science & Discovery
|
||||
{ word: 'equivalent', tiles: ['equ', 'iv', 'al', 'ent'], theme: 'science', clue: 'Equal in value, amount, function, or meaning' },
|
||||
{ word: 'hypothesis', tiles: ['hy', 'pot', 'he', 'sis'], theme: 'science', clue: 'A proposed explanation made on limited evidence' },
|
||||
{ word: 'laboratory', tiles: ['lab', 'ora', 'to', 'ry'], theme: 'science', clue: 'A room or building equipped for scientific experiments' },
|
||||
{ word: 'microscope', tiles: ['mi', 'cro', 'sco', 'pe'], theme: 'science', clue: 'Optical instrument for magnifying tiny objects' },
|
||||
{ word: 'phenomenon', tiles: ['phe', 'nom', 'en', 'on'], theme: 'science', clue: 'A remarkable fact or situation that is observed to happen' },
|
||||
|
||||
// Literature & Wordsmith
|
||||
{ word: 'dictionary', tiles: ['dic', 'tio', 'na', 'ry'], 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' },
|
||||
{ word: 'encyclopedia', tiles: ['en', 'cy', 'clo', 'pedia'], theme: 'words', clue: 'A book or set providing information on many subjects' },
|
||||
{ word: 'literature', tiles: ['li', 'ter', 'at', 'ure'], theme: 'words', clue: 'Written works, especially those considered of superior merit' },
|
||||
{ word: 'proverbial', tiles: ['pro', 'ver', 'bi', 'al'], theme: 'words', clue: 'Referred to in a proverb or well known' },
|
||||
|
||||
// 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' },
|
||||
{ word: 'backpacker', tiles: ['back', 'pa', 'ck', 'er'], theme: 'travel', clue: 'A traveler who journeys carrying their belongings' },
|
||||
{ word: 'locomotive', tiles: ['lo', 'co', 'mo', 'tive'], theme: 'travel', clue: 'A powered rail vehicle used for pulling trains' },
|
||||
{ word: 'continental', tiles: ['con', 'tin', 'en', 'tal'], theme: 'travel', clue: 'Forming or belonging to a continent' },
|
||||
{ word: 'navigation', tiles: ['na', 'vi', 'ga', 'tion'], theme: 'travel', clue: 'The process of accurately ascertaining one position and course' },
|
||||
{ word: 'voyagers', tiles: ['vo', 'ya', 'ge', 'rs'], theme: 'travel', clue: 'People who go on a long journey, typically by sea or space' },
|
||||
|
||||
// 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' },
|
||||
// Weather & Atmosphere
|
||||
{ word: 'meteorology', tiles: ['me', 'teo', 'rol', 'ogy'], theme: 'weather', clue: 'The science of atmospheric processes and forecasting' },
|
||||
{ word: 'temperatures', tiles: ['tem', 'per', 'at', 'ures'], theme: 'weather', clue: 'The degrees of heat present in substance or area' },
|
||||
{ word: 'precipitation', tiles: ['pre', 'cip', 'ita', 'tion'], theme: 'weather', clue: 'Rain, snow, sleet, or hail falling to the ground' },
|
||||
{ word: 'cloudburst', tiles: ['clo', 'ud', 'bur', 'st'], theme: 'weather', clue: 'A sudden, violent rainstorm' },
|
||||
{ word: 'thunderstorm', tiles: ['thun', 'der', 'sto', 'rm'], theme: 'weather', clue: 'A storm with thunder and lightning and heavy rain' },
|
||||
|
||||
// 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' },
|
||||
// Botany & Plants
|
||||
{ word: 'photosynthesis', tiles: ['pho', 'tos', 'yn', 'thesis'], theme: 'plants', clue: 'Process by which green plants synthesize nutrients' },
|
||||
{ word: 'horticulture', tiles: ['hor', 'tic', 'ul', 'ture'], theme: 'plants', clue: 'The art or practice of garden cultivation' },
|
||||
{ word: 'evergreen', tiles: ['ev', 'er', 'gre', 'en'], theme: 'plants', clue: 'A plant that retains green leaves throughout the year' },
|
||||
{ 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' },
|
||||
{ word: 'sunflowers', tiles: ['sun', 'flo', 'we', 'rs'], theme: 'plants', clue: 'Tall plants with very large, daisy-like yellow flowers' },
|
||||
|
||||
// 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' },
|
||||
// Grit & Endeavor
|
||||
{ word: 'determination', tiles: ['de', 'ter', 'mi', 'nation'], theme: 'endeavor', clue: 'Firmness of purpose; resoluteness' },
|
||||
{ word: 'courageous', tiles: ['cou', 'rag', 'eo', 'us'], theme: 'endeavor', clue: 'Not deterred by danger or pain; brave' },
|
||||
{ word: 'championship', tiles: ['cham', 'pion', 'sh', 'ip'], theme: 'endeavor', clue: 'A competition to decide the victor or champion' },
|
||||
{ word: 'achievement', tiles: ['ach', 'iev', 'em', 'ent'], theme: 'endeavor', clue: 'A thing done successfully with effort, skill, or courage' },
|
||||
{ word: 'perseverance', tiles: ['per', 'sev', 'era', 'nce'], theme: 'endeavor', clue: 'Persistence in doing something despite difficulty' },
|
||||
|
||||
// Ocean & Marine
|
||||
// Oceanic Depths
|
||||
{ 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' },
|
||||
{ word: 'underwater', tiles: ['un', 'der', 'wa', 'ter'], theme: 'ocean', clue: 'Situated or occurring below water surface' },
|
||||
{ word: 'crustaceans', tiles: ['cru', 'sta', 'ce', 'ans'], theme: 'ocean', clue: 'Aquatic arthropods like crabs, lobsters, and shrimp' },
|
||||
{ word: 'exploration', tiles: ['ex', 'plo', 'ra', 'tion'], theme: 'ocean', clue: 'The action of traveling through an unfamiliar area' },
|
||||
|
||||
// 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
|
||||
// Physics & Energy
|
||||
{ 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' }
|
||||
{ word: 'radioactive', tiles: ['rad', 'ioa', 'cti', 've'], theme: 'physics', clue: 'Emitting ionizing radiation from nuclei' },
|
||||
{ word: 'magnetism', tiles: ['mag', 'ne', 'ti', 'sm'], theme: 'physics', clue: 'A physical phenomenon produced by the motion of electric charge' },
|
||||
|
||||
// Additional 100+ unique words for Random Unlimited Generator
|
||||
{ word: 'kaleidoscope', tiles: ['kal', 'eid', 'osc', 'ope'], theme: 'arts', clue: 'Optical instrument with reflective surfaces showing patterns' },
|
||||
{ word: 'rollercoaster', tiles: ['rol', 'ler', 'coas', 'ter'], theme: 'fun', clue: 'Amusement park ride with steep slopes and curves' },
|
||||
{ word: 'firecracker', tiles: ['fi', 'rec', 'rac', 'ker'], theme: 'fun', clue: 'A loud explosive firework' },
|
||||
{ word: 'helicopter', tiles: ['he', 'li', 'cop', 'ter'], theme: 'travel', clue: 'Aircraft with horizontally rotating blades' },
|
||||
{ word: 'motorcycle', tiles: ['mo', 'tor', 'cy', 'cle'], theme: 'travel', clue: 'Two-wheeled vehicle powered by an engine' },
|
||||
{ word: 'candlestick', tiles: ['can', 'dle', 'sti', 'ck'], theme: 'craft', clue: 'A holder with a socket or spike for a candle' },
|
||||
{ word: 'peppermint', tiles: ['pep', 'per', 'mi', 'nt'], theme: 'food', clue: 'A pungent herb or sweet flavoring' },
|
||||
{ word: 'cheesecake', tiles: ['chee', 'se', 'ca', 'ke'], theme: 'food', clue: 'A rich sweet dessert made with soft cheese' },
|
||||
{ word: 'gingerbread', tiles: ['gin', 'ger', 'bre', 'ad'], theme: 'food', clue: 'A cake or cookie flavored with ginger and molasses' },
|
||||
{ word: 'blueberries', tiles: ['blue', 'ber', 'ri', 'es'], theme: 'food', clue: 'Small sweet blue-colored edible berries' },
|
||||
{ word: 'strawberries', tiles: ['straw', 'ber', 'ri', 'es'], theme: 'food', clue: 'Sweet juicy red fruit with seeds on surface' },
|
||||
{ word: 'waterproofing', tiles: ['wa', 'ter', 'pro', 'ofing'], theme: 'craft', clue: 'Making an object impervious to water' },
|
||||
{ word: 'troubleshooter', tiles: ['trou', 'ble', 'shoo', 'ter'], theme: 'tech', clue: 'Someone who identifies and solves problems' },
|
||||
{ word: 'heartwarming', tiles: ['hea', 'rtw', 'arm', 'ing'], theme: 'emotion', clue: 'Evoking feelings of happiness and contentment' },
|
||||
{ word: 'groundbreaking', tiles: ['gro', 'und', 'bre', 'aking'], theme: 'endeavor', clue: 'Innovative; applying new ideas' },
|
||||
{ word: 'brainstorming', tiles: ['bra', 'inst', 'orm', 'ing'], theme: 'mind', clue: 'Spontaneous group discussion to produce ideas' },
|
||||
{ word: 'hydroelectric', tiles: ['hyd', 'roe', 'lec', 'tric'], theme: 'physics', clue: 'Relating to generation of electricity using water flow' },
|
||||
{ word: 'aerodynamics', tiles: ['aer', 'ody', 'nam', 'ics'], theme: 'physics', clue: 'Study of forces and motion of air around objects' },
|
||||
{ word: 'superpower', tiles: ['su', 'per', 'po', 'wer'], theme: 'society', clue: 'An exceptionally powerful nation or ability' },
|
||||
{ word: 'leadership', tiles: ['lead', 'er', 'sh', 'ip'], theme: 'society', clue: 'The action of leading a group or organization' },
|
||||
{ word: 'brotherhood', tiles: ['bro', 'ther', 'ho', 'od'], theme: 'society', clue: 'An association or community of people' },
|
||||
{ word: 'windsurfers', tiles: ['wind', 'sur', 'fe', 'rs'], theme: 'sports', clue: 'Person who engages in board sailing' },
|
||||
{ word: 'paraglider', tiles: ['pa', 'rag', 'lid', 'er'], theme: 'sports', clue: 'Non-motorized, foot-launched glider aircraft' },
|
||||
{ word: 'thermometer', tiles: ['ther', 'mo', 'me', 'ter'], theme: 'science', clue: 'Instrument for measuring temperature' },
|
||||
{ word: 'barometer', tiles: ['ba', 'rom', 'et', 'er'], theme: 'science', clue: 'Instrument measuring atmospheric pressure' },
|
||||
{ word: 'speedometer', tiles: ['spee', 'dom', 'et', 'er'], theme: 'science', clue: 'Instrument on a vehicle indicating speed' },
|
||||
{ word: 'cartography', tiles: ['car', 'tog', 'ra', 'phy'], theme: 'science', clue: 'The science or practice of drawing maps' },
|
||||
{ word: 'oceanfront', tiles: ['oce', 'anf', 'ro', 'nt'], theme: 'nature', clue: 'Land facing directly toward the ocean' },
|
||||
{ word: 'rainforest', tiles: ['rain', 'fo', 're', 'st'], theme: 'nature', clue: 'A dense forest rich in biodiversity' },
|
||||
{ word: 'waterfalls', tiles: ['wa', 'ter', 'fa', 'lls'], theme: 'nature', clue: 'Cascade of water falling from a height' },
|
||||
{ word: 'dragonflies', tiles: ['dra', 'gon', 'fli', 'es'], theme: 'nature', clue: 'Fast-flying insects with long bodies and two pairs of wings' },
|
||||
{ word: 'sandwiches', tiles: ['sand', 'wi', 'ch', 'es'], theme: 'food', clue: 'Slices of bread with filling between them' },
|
||||
{ word: 'shortbread', tiles: ['sho', 'rtb', 're', 'ad'], theme: 'food', clue: 'A crisp rich crumbly biscuit' },
|
||||
{ word: 'blacksmith', tiles: ['bla', 'cks', 'mi', 'th'], theme: 'craft', clue: 'A person who makes and repairs things in iron' },
|
||||
{ word: 'silversmith', tiles: ['sil', 'ver', 'smi', 'th'], theme: 'craft', clue: 'A person who crafts objects out of silver' },
|
||||
{ word: 'coppersmith', tiles: ['cop', 'per', 'smi', 'th'], theme: 'craft', clue: 'A person who makes artifacts from copper' },
|
||||
{ word: 'locksmiths', tiles: ['loc', 'ksm', 'it', 'hs'], theme: 'craft', clue: 'People who make and repair locks' },
|
||||
{ word: 'woodworking', tiles: ['wood', 'wor', 'ki', 'ng'], theme: 'craft', clue: 'The activity or skill of making items from wood' },
|
||||
{ word: 'shipbuilder', tiles: ['ship', 'bui', 'ld', 'er'], theme: 'craft', clue: 'A person or business that designs and constructs ships' },
|
||||
{ word: 'stonecutter', tiles: ['sto', 'ne', 'cut', 'ter'], theme: 'craft', clue: 'A person who cuts, carves, or dresses stone' },
|
||||
{ word: 'glassblower', tiles: ['gla', 'ssb', 'low', 'er'], theme: 'craft', clue: 'A person who shapes molten glass by blowing air into it' },
|
||||
{ word: 'watchmakers', tiles: ['wat', 'chm', 'ake', 'rs'], theme: 'craft', clue: 'Artisans who make and repair watches' },
|
||||
{ word: 'matchmakers', tiles: ['mat', 'chm', 'ake', 'rs'], theme: 'society', clue: 'People who arrange marriages or partnerships' },
|
||||
{ word: 'homemakers', tiles: ['hom', 'em', 'ake', 'rs'], theme: 'society', clue: 'People who manage a household' },
|
||||
{ word: 'playmakers', tiles: ['pla', 'yma', 'ke', 'rs'], theme: 'sports', clue: 'Players who control the flow of the team offensive play' },
|
||||
{ word: 'gatekeepers', tiles: ['gat', 'eke', 'ep', 'ers'], theme: 'society', clue: 'Attendants controlling access through an entrance' },
|
||||
{ word: 'peacekeeper', tiles: ['pea', 'cek', 'eep', 'er'], theme: 'society', clue: 'A person maintaining peace, especially in conflict zones' },
|
||||
{ word: 'bookkeeper', tiles: ['boo', 'kke', 'ep', 'er'], theme: 'business', clue: 'A person whose job is to keep financial records' },
|
||||
{ word: 'shopkeeper', tiles: ['sho', 'pke', 'ep', 'er'], theme: 'business', clue: 'An owner or manager of a small shop' },
|
||||
{ word: 'innkeepers', tiles: ['inn', 'kee', 'pe', 'rs'], theme: 'business', clue: 'People who run an inn' },
|
||||
{ word: 'goalscorers', tiles: ['goa', 'lsc', 'ore', 'rs'], theme: 'sports', clue: 'Athletes who score goals in games' },
|
||||
{ word: 'cheerleader', tiles: ['che', 'erl', 'ead', 'er'], theme: 'sports', clue: 'A member of a team that leads cheering' },
|
||||
{ word: 'trendsetter', tiles: ['tre', 'nds', 'ett', 'er'], theme: 'society', clue: 'A person who leads the way in fashion or ideas' },
|
||||
{ word: 'bellwethers', tiles: ['bel', 'lwe', 'the', 'rs'], theme: 'society', clue: 'Something that leads or indicates future trends' },
|
||||
{ word: 'underwriter', tiles: ['und', 'erw', 'rit', 'er'], theme: 'business', clue: 'A company or person guaranteeing an undertaking' },
|
||||
{ word: 'copywriters', tiles: ['cop', 'ywr', 'ite', 'rs'], theme: 'business', clue: 'A person who writes text for advertising' },
|
||||
{ word: 'ghostwriter', tiles: ['gho', 'stw', 'rit', 'er'], theme: 'words', clue: 'A person hired to write literary or journalistic work' },
|
||||
{ word: 'screenwriter', tiles: ['scr', 'een', 'wri', 'ter'], theme: 'arts', clue: 'A person who writes screenplays for films' },
|
||||
{ word: 'playwrights', tiles: ['pla', 'ywr', 'igh', 'ts'], theme: 'arts', clue: 'People who write plays' },
|
||||
{ word: 'songwriters', tiles: ['son', 'gwr', 'ite', 'rs'], theme: 'arts', clue: 'Musicians who write musical compositions and lyrics' },
|
||||
{ word: 'headmasters', tiles: ['hea', 'dma', 'ste', 'rs'], theme: 'education', clue: 'Teachers in charge of a school' },
|
||||
{ word: 'ringmasters', tiles: ['rin', 'gma', 'ste', 'rs'], theme: 'circus', clue: 'The master of ceremonies in a circus' },
|
||||
{ word: 'grandmaster', tiles: ['gra', 'ndm', 'ast', 'er'], theme: 'games', clue: 'The highest title awarded to a chess player' },
|
||||
{ word: 'quarterback', tiles: ['qua', 'rte', 'rba', 'ck'], theme: 'sports', clue: 'A player in American football directing play' },
|
||||
{ word: 'sweatshirts', tiles: ['swe', 'atsh', 'ir', 'ts'], theme: 'clothes', clue: 'Loose warm casual cotton pullover shirts' },
|
||||
{ word: 'turtlenecks', tiles: ['tur', 'tle', 'nec', 'ks'], theme: 'clothes', clue: 'High, close-fitting turned-over collars' },
|
||||
{ word: 'windbreaker', tiles: ['win', 'dbr', 'eak', 'er'], theme: 'clothes', clue: 'A wind-resistant lightweight jacket' },
|
||||
{ word: 'rainjackets', tiles: ['rai', 'nja', 'cke', 'ts'], theme: 'clothes', clue: 'Water-resistant outer coats' },
|
||||
{ word: 'leatherback', tiles: ['lea', 'the', 'rba', 'ck'], theme: 'nature', clue: 'The largest living sea turtle with leathery carapace' },
|
||||
{ word: 'silverback', tiles: ['sil', 'ver', 'ba', 'ck'], theme: 'nature', clue: 'An older mature male mountain gorilla' },
|
||||
{ word: 'paddleboard', tiles: ['pad', 'dle', 'bo', 'ard'], theme: 'sports', clue: 'A long board propelled with a paddle' },
|
||||
{ word: 'springboard', tiles: ['spr', 'ing', 'bo', 'ard'], theme: 'sports', clue: 'A flexible board used in diving or gymnastics' },
|
||||
{ word: 'checkerboard', tiles: ['che', 'cke', 'rbo', 'ard'], theme: 'games', clue: 'A game board divided into sixty-four squares' },
|
||||
{ word: 'blackboards', tiles: ['bla', 'ckb', 'oar', 'ds'], theme: 'education', clue: 'Dark reusable writing surfaces for chalk' },
|
||||
{ word: 'whiteboards', tiles: ['whi', 'teb', 'oar', 'ds'], theme: 'education', clue: 'Glossy white boards for nonpermanent markers' },
|
||||
{ word: 'noticeboards', tiles: ['not', 'ice', 'boa', 'rds'], theme: 'society', clue: 'Boards for displaying notices or advertisements' },
|
||||
{ word: 'smorgasbord', tiles: ['smo', 'rga', 'sbo', 'rd'], theme: 'food', clue: 'A buffet offering a variety of hot and cold dishes' }
|
||||
];
|
||||
|
||||
console.log('Target words pool size:', targetWordsPool.length);
|
||||
// Merge expanded word list (skip invalid entries with a warning instead of failing)
|
||||
{
|
||||
const existing = new Set(targetWordsPool.map(w => w.word));
|
||||
let added = 0;
|
||||
for (const item of extraWords) {
|
||||
const problems = [];
|
||||
if (existing.has(item.word)) problems.push('duplicate word');
|
||||
if (item.tiles.length !== 4) problems.push('not 4 tiles');
|
||||
if (item.tiles.join('') !== item.word) problems.push(`tiles spell "${item.tiles.join('')}"`);
|
||||
if (!item.tiles.every(t => t.length >= 2)) problems.push('tile < 2 letters');
|
||||
if (new Set(item.tiles).size !== item.tiles.length) problems.push('repeated tile within word');
|
||||
if (!DICTIONARY_SET.has(item.word)) problems.push('not in runtime dictionary');
|
||||
if (problems.length) {
|
||||
console.warn(` Skipping extra word "${item.word}": ${problems.join(', ')}`);
|
||||
continue;
|
||||
}
|
||||
existing.add(item.word);
|
||||
targetWordsPool.push(item);
|
||||
added++;
|
||||
}
|
||||
console.log(`Merged ${added} extra target words.`);
|
||||
}
|
||||
|
||||
// Validate pool integrity
|
||||
for (const item of targetWordsPool) {
|
||||
if (item.tiles.join('') !== item.word) {
|
||||
throw new Error(`Word spelling mismatch: ${item.word} !== ${item.tiles.join('')}`);
|
||||
}
|
||||
if (!item.tiles.every(t => t.length >= 2)) {
|
||||
throw new Error(`Word contains tile < 2 chars: ${item.word} -> ${JSON.stringify(item.tiles)}`);
|
||||
}
|
||||
if (item.tiles.length !== 4) {
|
||||
throw new Error(`Word does not have 4 tiles: ${item.word}`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Target words pool verified! Total words:', targetWordsPool.length);
|
||||
|
||||
// Generate 30 curated daily and themed puzzles
|
||||
const dailyPuzzlesDefs = [
|
||||
{
|
||||
id: '2026-10-23',
|
||||
@@ -166,7 +296,7 @@ const dailyPuzzlesDefs = [
|
||||
title: 'Daily Puzzle — Oct 27, 2026',
|
||||
theme: 'Harmony & Arts',
|
||||
difficulty: 'Normal',
|
||||
words: ['symphony', 'masterpiece', 'performance', 'exhibition', 'creativity']
|
||||
words: ['symphonically', 'masterpiece', 'calligraphy', 'exhibition', 'creativity']
|
||||
},
|
||||
{
|
||||
id: '2026-10-28',
|
||||
@@ -174,7 +304,7 @@ const dailyPuzzlesDefs = [
|
||||
title: 'Daily Puzzle — Oct 28, 2026',
|
||||
theme: 'Digital Future',
|
||||
difficulty: 'Normal',
|
||||
words: ['technology', 'electronic', 'automation', 'innovation', 'computation']
|
||||
words: ['technology', 'electronic', 'automation', 'semiconductor', 'cybersecurity']
|
||||
},
|
||||
{
|
||||
id: '2026-10-29',
|
||||
@@ -182,7 +312,7 @@ const dailyPuzzlesDefs = [
|
||||
title: 'Daily Puzzle — Oct 29, 2026',
|
||||
theme: 'Celebrations',
|
||||
difficulty: 'Easy',
|
||||
words: ['celebration', 'communication', 'relationship', 'opportunity', 'conversation']
|
||||
words: ['celebration', 'fellowship', 'generosity', 'opportunity', 'marshmallow']
|
||||
},
|
||||
{
|
||||
id: '2026-10-30',
|
||||
@@ -190,7 +320,7 @@ const dailyPuzzlesDefs = [
|
||||
title: 'Daily Puzzle — Oct 30, 2026',
|
||||
theme: 'Wild Kingdom',
|
||||
difficulty: 'Normal',
|
||||
words: ['biodiversity', 'environment', 'caterpillar', 'underwater', 'thunderstorm']
|
||||
words: ['biodiversity', 'environment', 'caterpillar', 'wilderness', 'chameleon']
|
||||
},
|
||||
{
|
||||
id: '2026-10-31',
|
||||
@@ -198,7 +328,7 @@ const dailyPuzzlesDefs = [
|
||||
title: 'Daily Puzzle — Oct 31, 2026',
|
||||
theme: 'Mysteries & Legends',
|
||||
difficulty: 'Challenging',
|
||||
words: ['mysterious', 'determination', 'perseverance', 'investigation', 'anticipation']
|
||||
words: ['mysterious', 'supernatural', 'apparition', 'enchanted', 'miraculous']
|
||||
},
|
||||
{
|
||||
id: '2026-10-22',
|
||||
@@ -206,7 +336,7 @@ const dailyPuzzlesDefs = [
|
||||
title: 'Daily Puzzle — Oct 22, 2026',
|
||||
theme: 'Scientific Insight',
|
||||
difficulty: 'Normal',
|
||||
words: ['required', 'equivalent', 'objection', 'justification', 'mysterious']
|
||||
words: ['equivalent', 'hypothesis', 'laboratory', 'microscope', 'phenomenon']
|
||||
},
|
||||
{
|
||||
id: '2026-10-21',
|
||||
@@ -214,7 +344,7 @@ const dailyPuzzlesDefs = [
|
||||
title: 'Daily Puzzle — Oct 21, 2026',
|
||||
theme: 'Wordsmith Almanac',
|
||||
difficulty: 'Normal',
|
||||
words: ['vocabulary', 'encyclopedia', 'dictionary', 'manuscript', 'translation']
|
||||
words: ['dictionary', 'manuscript', 'encyclopedia', 'literature', 'proverbial']
|
||||
},
|
||||
{
|
||||
id: '2026-10-20',
|
||||
@@ -222,7 +352,7 @@ const dailyPuzzlesDefs = [
|
||||
title: 'Daily Puzzle — Oct 20, 2026',
|
||||
theme: 'Globe Trekker',
|
||||
difficulty: 'Normal',
|
||||
words: ['destination', 'navigation', 'continental', 'expedition', 'exploration']
|
||||
words: ['backpacker', 'locomotive', 'continental', 'navigation', 'voyagers']
|
||||
},
|
||||
{
|
||||
id: '2026-10-19',
|
||||
@@ -230,7 +360,7 @@ const dailyPuzzlesDefs = [
|
||||
title: 'Daily Puzzle — Oct 19, 2026',
|
||||
theme: 'Atmospheric Skies',
|
||||
difficulty: 'Challenging',
|
||||
words: ['temperatures', 'precipitation', 'meteorology', 'hibernation', 'illumination']
|
||||
words: ['meteorology', 'temperatures', 'precipitation', 'stratosphere', 'cloudburst']
|
||||
},
|
||||
{
|
||||
id: '2026-10-18',
|
||||
@@ -238,7 +368,7 @@ const dailyPuzzlesDefs = [
|
||||
title: 'Daily Puzzle — Oct 18, 2026',
|
||||
theme: 'Green Oasis',
|
||||
difficulty: 'Normal',
|
||||
words: ['photosynthesis', 'chlorophyll', 'horticulture', 'germination', 'cultivation']
|
||||
words: ['photosynthesis', 'horticulture', 'evergreen', 'germination', 'sunflowers']
|
||||
},
|
||||
{
|
||||
id: '2026-10-17',
|
||||
@@ -246,7 +376,7 @@ const dailyPuzzlesDefs = [
|
||||
title: 'Daily Puzzle — Oct 17, 2026',
|
||||
theme: 'Grit & Glory',
|
||||
difficulty: 'Normal',
|
||||
words: ['determination', 'perseverance', 'accomplished', 'achievement', 'distinguished']
|
||||
words: ['determination', 'courageous', 'championship', 'achievement', 'perseverance']
|
||||
},
|
||||
{
|
||||
id: '2026-10-16',
|
||||
@@ -254,7 +384,7 @@ const dailyPuzzlesDefs = [
|
||||
title: 'Daily Puzzle — Oct 16, 2026',
|
||||
theme: 'Oceanic Depths',
|
||||
difficulty: 'Challenging',
|
||||
words: ['oceanography', 'submersible', 'constellation', 'mediterranean', 'exploration']
|
||||
words: ['oceanography', 'submersible', 'underwater', 'crustaceans', 'exploration']
|
||||
},
|
||||
{
|
||||
id: '2026-10-15',
|
||||
@@ -262,7 +392,7 @@ const dailyPuzzlesDefs = [
|
||||
title: 'Daily Puzzle — Oct 15, 2026',
|
||||
theme: 'Energy & Waves',
|
||||
difficulty: 'Expert',
|
||||
words: ['electricity', 'acceleration', 'thermodynamic', 'equilibrium', 'radioactivity']
|
||||
words: ['electricity', 'thermodynamic', 'equilibrium', 'radioactive', 'magnetism']
|
||||
}
|
||||
];
|
||||
|
||||
@@ -281,7 +411,23 @@ for (const def of dailyPuzzlesDefs) {
|
||||
return found.tiles;
|
||||
});
|
||||
|
||||
const solved = solveBoard(quartets);
|
||||
const allTiles = quartets.flat();
|
||||
// STRICT ASSERTIONS
|
||||
if (new Set(allTiles).size !== 20) {
|
||||
const counts = {};
|
||||
allTiles.forEach(t => counts[t] = (counts[t] || 0) + 1);
|
||||
const dupes = Object.entries(counts).filter(([_, c]) => c > 1);
|
||||
throw new Error(`Puzzle ${def.id} has duplicate tiles: ${JSON.stringify(dupes)}`);
|
||||
}
|
||||
if (allTiles.some(t => t.length < 2)) {
|
||||
throw new Error(`Puzzle ${def.id} has a tile < 2 chars: ${JSON.stringify(allTiles)}`);
|
||||
}
|
||||
|
||||
const solved = solveBoard(quartets, 30);
|
||||
|
||||
if (solved.wordCount > 30) {
|
||||
throw new Error(`Puzzle ${def.id} exceeds 30 words: ${solved.wordCount}`);
|
||||
}
|
||||
|
||||
// Add clues to target quartiles
|
||||
const quartileDetails = def.words.map(w => {
|
||||
|
||||
325
scripts/extra-words.mjs
Normal file
325
scripts/extra-words.mjs
Normal file
@@ -0,0 +1,325 @@
|
||||
// Expanded target-word pool for Quartiles.
|
||||
// Format per line: word|t1-t2-t3-t4|theme|clue
|
||||
// Rules (validated in build-all-data.mjs):
|
||||
// - tiles join exactly to the word
|
||||
// - exactly 4 tiles, each >= 2 letters
|
||||
// - no repeated tile within a single word
|
||||
const RAW = `
|
||||
alligator|al-li-ga-tor|animals|Large reptile of southern swamps
|
||||
armadillo|ar-ma-dil-lo|animals|Burrowing mammal with a bony armored shell
|
||||
crocodile|cro-co-di-le|animals|Large aquatic reptile with powerful jaws
|
||||
porcupine|por-cu-pi-ne|animals|Rodent covered in sharp protective quills
|
||||
salamander|sa-la-man-der|animals|Lizard-like amphibian with moist skin
|
||||
orangutan|or-an-gu-tan|animals|Red-haired great ape of Borneo and Sumatra
|
||||
kangaroos|kan-ga-ro-os|animals|Hopping marsupials of Australia
|
||||
centipede|cen-ti-pe-de|animals|Arthropod with a great many legs
|
||||
tarantula|ta-ran-tu-la|animals|Large hairy spider
|
||||
jellyfish|jel-ly-fi-sh|animals|Free-swimming sea creature with stinging tentacles
|
||||
seahorses|sea-ho-rs-es|animals|Small upright fish with horse-like heads
|
||||
nightingale|nigh-tin-ga-le|animals|Songbird famous for singing at night
|
||||
rhinoceros|rhi-no-ce-ros|animals|Large horned herbivore of Africa and Asia
|
||||
hippopotamus|hip-po-pota-mus|animals|Massive semi-aquatic African mammal
|
||||
chimpanzee|chim-pa-nz-ee|animals|Intelligent African great ape
|
||||
wolverine|wol-ve-ri-ne|animals|Fierce carnivore of northern forests
|
||||
mockingbird|mock-ing-bi-rd|animals|Bird that imitates the songs of others
|
||||
roadrunner|ro-ad-run-ner|animals|Fast-running desert bird
|
||||
platypus|pl-at-yp-us|animals|Egg-laying mammal with a duck-like bill
|
||||
scorpions|sc-or-pi-ons|animals|Arachnids with a venomous curved tail
|
||||
octopuses|oc-to-pu-ses|animals|Eight-armed sea creatures
|
||||
barracuda|bar-ra-cu-da|animals|Predatory fish with fang-like teeth
|
||||
cockroaches|cock-ro-ach-es|animals|Hardy scuttling household insects
|
||||
cappuccino|cap-pu-cci-no|food|Espresso topped with frothy milk
|
||||
spaghetti|sp-ag-het-ti|food|Long thin strands of pasta
|
||||
macaroni|ma-ca-ro-ni|food|Small tube-shaped pasta
|
||||
broccoli|br-oc-co-li|food|Green vegetable with tree-like florets
|
||||
pineapple|pi-ne-ap-ple|food|Tropical fruit with spiky skin
|
||||
watermelon|wa-ter-mel-on|food|Large juicy summer fruit with a green rind
|
||||
pomegranate|pom-egr-an-ate|food|Fruit packed with juicy red seeds
|
||||
chocolate|cho-co-la-te|food|Sweet treat made from roasted cacao
|
||||
cinnamon|ci-nn-am-on|food|Warm spice made from tree bark
|
||||
blackberry|bla-ckb-er-ry|food|Dark bramble fruit
|
||||
raspberry|ras-pb-er-ry|food|Soft red berry with a hollow core
|
||||
tangerine|tan-ge-ri-ne|food|Small, easy-to-peel citrus fruit
|
||||
mozzarella|moz-za-rel-la|food|Soft white Italian cheese
|
||||
guacamole|gua-ca-mo-le|food|Avocado-based Mexican dip
|
||||
margarine|mar-ga-ri-ne|food|Butter substitute made from vegetable oils
|
||||
casserole|cas-se-ro-le|food|Dish slow-cooked in the oven
|
||||
croissant|cr-ois-sa-nt|food|Flaky crescent-shaped French pastry
|
||||
hamburger|ham-bu-rg-er|food|Ground beef patty served in a bun
|
||||
pancakes|pa-nc-ak-es|food|Flat breakfast cakes cooked on a griddle
|
||||
marmalade|mar-ma-la-de|food|Citrus fruit preserve
|
||||
butterscotch|but-ters-cot-ch|food|Candy made from brown sugar and butter
|
||||
lemonade|le-mo-na-de|food|Sweetened drink made with lemon juice
|
||||
peppercorn|pep-per-co-rn|food|Dried berry ground into black pepper
|
||||
artichoke|ar-ti-cho-ke|food|Edible thistle flower bud
|
||||
asparagus|as-pa-ra-gus|food|Spring vegetable with tender green spears
|
||||
cauliflower|cau-li-flo-wer|food|White-headed cabbage-family vegetable
|
||||
vegetables|ve-ge-ta-bles|food|Edible plants or plant parts
|
||||
dumplings|dum-pl-in-gs|food|Small balls of dough, often filled
|
||||
meatballs|me-at-ba-lls|food|Rolled balls of seasoned ground meat
|
||||
honeycomb|ho-ney-co-mb|food|Wax structure where bees store honey
|
||||
cheeseburger|chee-se-bur-ger|food|Hamburger topped with melted cheese
|
||||
sauerkraut|sau-er-kra-ut|food|Finely cut fermented cabbage
|
||||
breakfast|bre-ak-fa-st|food|The first meal of the day
|
||||
basketball|bas-ket-ba-ll|sports|Game of shooting a ball through a hoop
|
||||
volleyball|vol-ley-ba-ll|sports|Game of hitting a ball over a high net
|
||||
badminton|bad-mi-nt-on|sports|Racket sport played with a shuttlecock
|
||||
gymnastics|gym-nas-ti-cs|sports|Sport of balance, strength, and flips
|
||||
skateboard|ska-te-bo-ard|sports|Wheeled board ridden for tricks
|
||||
snowboarding|snow-boar-di-ng|sports|Sliding down snowy slopes on one board
|
||||
marathon|ma-ra-th-on|sports|Long-distance running race
|
||||
wrestling|wre-st-li-ng|sports|Grappling sport of pins and holds
|
||||
lacrosse|la-cr-os-se|sports|Field sport played with netted sticks
|
||||
tournament|tour-na-me-nt|sports|A series of contests to find a champion
|
||||
crossword|cro-ss-wo-rd|games|Grid puzzle solved from clues
|
||||
backgammon|ba-ckg-am-mon|games|Ancient board game of dice and checkers
|
||||
dominoes|do-mi-no-es|games|Game of matching spotted tiles
|
||||
trampoline|tram-po-li-ne|sports|Springy mat for bouncing
|
||||
goalkeeper|goal-ke-ep-er|sports|Player who guards the net
|
||||
swimming|sw-im-mi-ng|sports|Moving through water using limbs
|
||||
surfboard|su-rf-bo-ard|sports|Board used for riding waves
|
||||
racquetball|rac-quet-ba-ll|sports|Fast indoor racket sport
|
||||
scoreboard|sco-re-bo-ard|sports|Large display showing a game's points
|
||||
touchdown|to-uch-do-wn|sports|Six-point score in American football
|
||||
cartwheel|ca-rt-whe-el|sports|Sideways handspring with arms and legs extended
|
||||
hopscotch|hop-sc-ot-ch|games|Playground hopping game drawn in chalk
|
||||
checkmate|che-ck-ma-te|games|Winning position in chess
|
||||
astronaut|as-tro-na-ut|jobs|Person trained to travel into space
|
||||
carpenter|ca-rp-en-ter|jobs|Person who builds things from wood
|
||||
electrician|elec-tri-ci-an|jobs|Person who installs and repairs wiring
|
||||
firefighter|fire-fig-ht-er|jobs|Person who puts out fires
|
||||
journalist|jour-na-li-st|jobs|Person who writes news stories
|
||||
librarian|li-bra-ri-an|jobs|Person who manages a collection of books
|
||||
magician|ma-gi-ci-an|jobs|Performer of illusions and tricks
|
||||
mechanic|me-ch-an-ic|jobs|Person who repairs engines
|
||||
musician|mu-si-ci-an|jobs|Person who plays music
|
||||
pharmacist|phar-ma-ci-st|jobs|Person who prepares medicines
|
||||
photographer|pho-to-gra-pher|jobs|Person who takes pictures
|
||||
professor|pr-of-ess-or|jobs|University teacher of the highest rank
|
||||
scientist|sci-en-ti-st|jobs|Person who studies the natural world
|
||||
detective|de-tec-ti-ve|jobs|Person who investigates crimes
|
||||
architect|ar-chi-te-ct|jobs|Person who designs buildings
|
||||
veterinarian|vet-eri-nar-ian|jobs|Doctor for animals
|
||||
lifeguard|li-fe-gu-ard|jobs|Person who watches over swimmers
|
||||
gardener|ga-rd-en-er|jobs|Person who tends plants
|
||||
lumberjack|lum-ber-ja-ck|jobs|Person who fells trees
|
||||
accountant|ac-cou-nt-ant|jobs|Person who keeps financial accounts
|
||||
translator|tra-ns-la-tor|jobs|Person who converts text between languages
|
||||
programmer|pro-gr-am-mer|jobs|Person who writes computer code
|
||||
babysitter|ba-by-sit-ter|jobs|Person who looks after children
|
||||
umbrella|um-br-el-la|home|Folding canopy that keeps off rain
|
||||
telephone|te-le-pho-ne|home|Device for talking over a distance
|
||||
television|te-le-vi-sion|home|Screen for watching broadcast shows
|
||||
refrigerator|re-fri-ger-ator|home|Appliance that keeps food cold
|
||||
dishwasher|dish-wa-sh-er|home|Appliance that cleans plates
|
||||
microwave|mi-cro-wa-ve|home|Oven that heats food quickly
|
||||
calculator|cal-cu-la-tor|home|Device for doing arithmetic
|
||||
binoculars|bi-no-cu-lars|home|Two-lensed device for seeing far away
|
||||
thermostat|ther-mo-st-at|home|Device that regulates temperature
|
||||
wheelbarrow|whe-el-bar-row|home|One-wheeled cart for hauling loads
|
||||
lawnmower|la-wn-mow-er|home|Machine for cutting grass
|
||||
flashlight|fla-sh-lig-ht|home|Portable battery-powered light
|
||||
toothbrush|too-th-br-ush|home|Small brush for cleaning teeth
|
||||
pillowcase|pil-low-ca-se|home|Removable cover for a pillow
|
||||
wardrobe|wa-rd-ro-be|home|Tall cabinet for hanging clothes
|
||||
bookshelf|bo-ok-sh-elf|home|Shelf for holding books
|
||||
chandelier|chan-de-li-er|home|Decorative hanging light fixture
|
||||
typewriter|ty-pe-wri-ter|home|Mechanical machine for typing
|
||||
paperclip|pa-per-cl-ip|home|Bent wire for holding sheets together
|
||||
scissors|sc-is-so-rs|home|Two-bladed cutting tool
|
||||
envelope|en-ve-lo-pe|home|Paper sleeve for mailing letters
|
||||
suitcase|su-it-ca-se|home|Case for carrying clothes when traveling
|
||||
candlelight|can-dle-li-ght|home|Soft glow from a burning wick
|
||||
fireplace|fi-re-pla-ce|home|Hearth for an indoor fire
|
||||
staircase|sta-ir-ca-se|home|Set of steps between floors
|
||||
doorbell|do-or-be-ll|home|Button that chimes when visitors arrive
|
||||
windowsill|win-dow-si-ll|home|Ledge at the bottom of a window
|
||||
furniture|fur-ni-tu-re|home|Chairs, tables, beds, and the like
|
||||
cupboard|cu-pb-oa-rd|home|Cabinet with shelves and doors
|
||||
headphones|hea-dp-ho-nes|tech|Speakers worn over the ears
|
||||
keyboard|ke-yb-oa-rd|tech|Panel of keys for typing
|
||||
computer|co-mp-ut-er|tech|Electronic machine that processes data
|
||||
smartphone|sma-rt-pho-ne|tech|Pocket-sized phone with apps
|
||||
spreadsheet|spr-ead-she-et|tech|Grid of cells for calculations
|
||||
password|pa-ss-wo-rd|tech|Secret word for logging in
|
||||
algorithm|al-go-ri-thm|tech|Step-by-step procedure for solving a problem
|
||||
satellite|sa-tel-li-te|tech|Object orbiting a planet
|
||||
batteries|bat-te-ri-es|tech|Cells that store electrical energy
|
||||
robotics|ro-bo-ti-cs|tech|Engineering of automated machines
|
||||
database|da-ta-ba-se|tech|Organized store of information
|
||||
software|so-ft-wa-re|tech|Programs that run on a computer
|
||||
hardware|ha-rd-wa-re|tech|Physical parts of a computer
|
||||
internet|in-te-rn-et|tech|Global network of computers
|
||||
download|do-wn-lo-ad|tech|Copy a file from the web
|
||||
wireless|wi-re-le-ss|tech|Without cables
|
||||
microphone|mi-cro-pho-ne|tech|Device that picks up sound
|
||||
avalanche|av-al-an-che|nature|Mass of snow rushing down a mountain
|
||||
hurricane|hur-ri-ca-ne|nature|Powerful tropical storm
|
||||
earthquake|ear-th-qua-ke|nature|Sudden shaking of the ground
|
||||
tornadoes|tor-na-do-es|nature|Violently rotating columns of air
|
||||
landscape|la-nd-sc-ape|nature|All the visible features of an area of land
|
||||
mountains|mou-nt-ai-ns|nature|Very high natural elevations of land
|
||||
peninsula|pe-nin-su-la|nature|Land almost surrounded by water
|
||||
archipelago|ar-chi-pel-ago|nature|Group of islands
|
||||
riverbank|ri-ver-ba-nk|nature|Land along the edge of a river
|
||||
sandstone|sa-nd-sto-ne|nature|Rock formed from compressed sand
|
||||
limestone|li-me-sto-ne|nature|Rock formed from ancient shells
|
||||
grassland|gra-ss-la-nd|nature|Large open area covered in grass
|
||||
moonlight|mo-on-li-ght|nature|Light reflected from the moon
|
||||
sunshine|su-ns-hi-ne|nature|Direct light from the sun
|
||||
starlight|st-ar-li-ght|nature|Light from distant stars
|
||||
rainbows|ra-in-bo-ws|nature|Arcs of color after rain
|
||||
snowflake|sn-ow-fla-ke|nature|Single ice crystal falling from the sky
|
||||
lightning|li-ght-ni-ng|nature|Flash of electricity in a storm
|
||||
blizzard|bl-iz-za-rd|nature|Severe snowstorm with strong winds
|
||||
continent|con-ti-ne-nt|nature|One of Earth's large landmasses
|
||||
countryside|coun-try-si-de|nature|Rural land outside towns
|
||||
coastline|coa-st-li-ne|nature|Where land meets the sea
|
||||
wildflower|wi-ld-flow-er|nature|Flower growing without cultivation
|
||||
butterfly|bu-tt-er-fly|nature|Insect with large colorful wings
|
||||
mushrooms|mu-sh-ro-oms|nature|Fungi with caps and stems
|
||||
seashells|sea-sh-el-ls|nature|Shells found on the beach
|
||||
driftwood|dri-ft-wo-od|nature|Wood washed ashore by water
|
||||
happiness|hap-pi-ne-ss|emotion|State of being glad
|
||||
excitement|ex-ci-te-ment|emotion|Feeling of great eagerness
|
||||
confidence|con-fi-den-ce|emotion|Belief in one's own abilities
|
||||
gratitude|gra-ti-tu-de|emotion|Feeling of thankfulness
|
||||
kindness|ki-nd-ne-ss|emotion|Quality of being friendly and caring
|
||||
curiosity|cu-ri-osi-ty|emotion|Strong desire to know or learn
|
||||
enthusiasm|en-thu-si-asm|emotion|Intense enjoyment and interest
|
||||
patience|pa-ti-en-ce|emotion|Ability to wait calmly
|
||||
loneliness|lo-ne-li-ness|emotion|Sadness from being alone
|
||||
nostalgia|no-st-al-gia|emotion|Wistful longing for the past
|
||||
optimistic|op-ti-mis-tic|emotion|Hopeful about the future
|
||||
wonderful|won-de-rf-ul|emotion|Inspiring delight
|
||||
beautiful|be-au-ti-ful|emotion|Pleasing to the senses
|
||||
delightful|de-li-ght-ful|emotion|Causing great pleasure
|
||||
fantastic|fan-ta-st-ic|emotion|Extraordinarily good
|
||||
generous|ge-ne-ro-us|emotion|Freely giving
|
||||
cheerful|ch-ee-rf-ul|emotion|Noticeably happy
|
||||
peaceful|pe-ac-ef-ul|emotion|Free from disturbance
|
||||
mischievous|mis-chie-vo-us|emotion|Playfully causing trouble
|
||||
hilarious|hi-la-ri-ous|emotion|Extremely funny
|
||||
ambitious|am-bi-ti-ous|emotion|Strongly driven to succeed
|
||||
fearless|fe-ar-le-ss|emotion|Lacking fear; bold
|
||||
friendliness|fri-end-li-ness|emotion|Quality of being warm toward others
|
||||
forgiveness|for-gi-ve-ness|emotion|Act of pardoning a wrong
|
||||
compassion|com-pas-si-on|emotion|Sympathy for the suffering of others
|
||||
serendipity|ser-en-dip-ity|emotion|Happy accident or lucky discovery
|
||||
celebrate|ce-le-bra-te|emotion|Mark a happy occasion
|
||||
passport|pa-ss-po-rt|travel|Document for crossing borders
|
||||
lighthouse|li-ght-hou-se|travel|Tower with a guiding light for ships
|
||||
submarine|sub-ma-ri-ne|travel|Vessel that travels underwater
|
||||
sailboat|sa-il-bo-at|travel|Boat propelled by wind
|
||||
destination|des-ti-na-tion|travel|Place one is traveling to
|
||||
vacation|va-ca-ti-on|travel|Time off for rest or travel
|
||||
itinerary|iti-ne-ra-ry|travel|Planned route of a journey
|
||||
souvenir|so-uv-en-ir|travel|Keepsake from a trip
|
||||
adventure|ad-ven-tu-re|travel|Exciting or daring experience
|
||||
expedition|ex-pe-di-tion|travel|Journey with a purpose
|
||||
railroad|ra-il-ro-ad|travel|Track for trains
|
||||
motorway|mo-to-rw-ay|travel|Major high-speed road
|
||||
crossroads|cro-ss-ro-ads|travel|Where two roads meet
|
||||
campground|camp-gr-ou-nd|travel|Area for pitching tents
|
||||
hitchhiker|hit-ch-hi-ker|travel|Person traveling by free rides
|
||||
cathedral|ca-the-dr-al|places|Principal church of a diocese
|
||||
monastery|mo-nas-te-ry|places|Home of a community of monks
|
||||
observatory|ob-ser-va-tory|places|Building with telescopes for stargazing
|
||||
playground|play-gr-ou-nd|places|Outdoor area for children to play
|
||||
marketplace|mar-ket-pla-ce|places|Open area where goods are sold
|
||||
restaurant|res-tau-ra-nt|places|Place where meals are served
|
||||
supermarket|su-per-mar-ket|places|Large self-service grocery store
|
||||
university|uni-ver-si-ty|places|Institution of higher learning
|
||||
classroom|cl-ass-ro-om|places|Room where lessons are taught
|
||||
apartment|apa-rt-me-nt|places|Set of rooms for living in
|
||||
courthouse|co-ur-tho-use|places|Building where trials are held
|
||||
greenhouse|gre-en-hou-se|places|Glass building for growing plants
|
||||
warehouse|wa-re-hou-se|places|Large building for storing goods
|
||||
farmhouse|fa-rm-hou-se|places|Main house on a farm
|
||||
hospital|ho-sp-it-al|places|Place where the sick are treated
|
||||
aquarium|aq-ua-ri-um|places|Tank or building housing aquatic life
|
||||
orchestra|or-che-st-ra|arts|Large group of instrumental musicians
|
||||
saxophone|sax-op-ho-ne|arts|Brass-bodied reed instrument used in jazz
|
||||
xylophone|xy-lo-pho-ne|arts|Instrument of wooden bars struck with mallets
|
||||
harmonica|har-mo-ni-ca|arts|Small mouth organ
|
||||
accordion|ac-cor-di-on|arts|Squeezebox instrument with bellows
|
||||
clarinet|cl-ar-in-et|arts|Woodwind with a single reed
|
||||
trombone|tr-om-bo-ne|arts|Brass instrument with a slide
|
||||
tambourine|tam-bou-ri-ne|arts|Hand drum with jingling discs
|
||||
violinist|vi-ol-in-ist|arts|Person who plays the violin
|
||||
melodious|me-lo-di-ous|arts|Pleasant-sounding; tuneful
|
||||
painting|pa-in-ti-ng|arts|Picture made with paint
|
||||
sculpture|scu-lp-tu-re|arts|Art made by carving or modeling
|
||||
portrait|po-rt-ra-it|arts|Painting or photo of a person
|
||||
animation|ani-ma-ti-on|arts|Technique of making drawings appear to move
|
||||
cartoonist|car-to-on-ist|arts|Person who draws comics
|
||||
storyteller|sto-ry-tel-ler|arts|Person who tells tales
|
||||
novelist|no-ve-li-st|arts|Writer of novels
|
||||
illustrator|il-lus-tra-tor|arts|Person who draws pictures for books
|
||||
soundtrack|so-und-tra-ck|arts|Music accompanying a film
|
||||
spotlight|spo-tl-ig-ht|arts|Strong beam of light on a performer
|
||||
ballerina|bal-le-ri-na|arts|Female ballet dancer
|
||||
symphony|sy-mp-ho-ny|arts|Elaborate composition for orchestra
|
||||
masquerade|mas-que-ra-de|arts|Party where guests wear masks
|
||||
dinosaur|di-no-sa-ur|history|Extinct prehistoric reptile
|
||||
pyramids|py-ra-mi-ds|history|Ancient Egyptian monumental tombs
|
||||
gladiator|gla-di-at-or|history|Roman arena fighter
|
||||
knighthood|kni-ght-ho-od|history|Rank or status of a knight
|
||||
wizardry|wi-za-rd-ry|fantasy|The art of magic
|
||||
treasure|tr-ea-su-re|fantasy|Hoard of valuable riches
|
||||
shipwreck|sh-ip-wre-ck|history|Destruction of a ship at sea
|
||||
labyrinth|la-by-rin-th|fantasy|Complicated maze
|
||||
mythology|my-tho-lo-gy|fantasy|Collection of traditional myths
|
||||
legendary|le-gen-da-ry|fantasy|Famous; described in legends
|
||||
invisible|in-vi-si-ble|fantasy|Unable to be seen
|
||||
werewolf|we-re-wo-lf|fantasy|Person who turns into a wolf
|
||||
vampires|va-mp-ir-es|fantasy|Blood-drinking creatures of legend
|
||||
revolution|re-vo-lu-tion|history|Forcible overthrow of a government
|
||||
independence|in-de-pen-dence|history|Freedom from outside control
|
||||
democracy|de-mo-cra-cy|history|Government by the people
|
||||
parliament|par-lia-me-nt|history|Legislative assembly
|
||||
ambassador|am-bas-sa-dor|history|Diplomat representing a country abroad
|
||||
president|pre-si-de-nt|history|Elected head of a republic
|
||||
government|go-ver-nm-ent|history|Body that governs a nation
|
||||
constitution|con-sti-tu-tion|history|Founding legal document of a nation
|
||||
afternoon|af-ter-no-on|everyday|Time between noon and evening
|
||||
yesterday|yes-te-rd-ay|everyday|The day before today
|
||||
tomorrow|to-mo-rr-ow|everyday|The day after today
|
||||
calendar|ca-le-nd-ar|everyday|Chart of days and months
|
||||
everything|ev-ery-thi-ng|everyday|All things
|
||||
somewhere|so-me-whe-re|everyday|In or to some place
|
||||
basement|ba-se-me-nt|everyday|Floor below ground level
|
||||
newspaper|ne-ws-pa-per|everyday|Daily printed news publication
|
||||
magazine|ma-ga-zi-ne|everyday|Periodical with articles and photos
|
||||
alphabet|al-ph-ab-et|education|Set of letters of a language
|
||||
vocabulary|vo-ca-bu-lary|education|Body of words a person knows
|
||||
homework|ho-me-wo-rk|education|Schoolwork done at home
|
||||
notebook|no-te-bo-ok|education|Book of blank pages for notes
|
||||
paintbrush|pa-int-bru-sh|education|Brush for applying paint
|
||||
handwriting|hand-wri-ti-ng|education|Writing done by hand
|
||||
spelling|sp-el-li-ng|education|Forming words from letters correctly
|
||||
mathematics|ma-the-mat-ics|education|Science of numbers and shapes
|
||||
geography|ge-og-ra-phy|education|Study of Earth's features
|
||||
chemistry|che-mi-st-ry|education|Science of substances and reactions
|
||||
experiment|ex-pe-ri-ment|science|Scientific test of a hypothesis
|
||||
discovery|di-sco-ve-ry|science|Act of finding something new
|
||||
invention|in-ven-ti-on|science|Something newly created
|
||||
skeleton|sk-el-et-on|science|Framework of bones
|
||||
vitamins|vi-ta-mi-ns|health|Nutrients needed in small amounts
|
||||
medicine|me-di-ci-ne|health|Substance used to treat illness
|
||||
bandages|ba-nd-ag-es|health|Strips of material for wounds
|
||||
ambulance|am-bu-la-nce|health|Vehicle for emergency patients
|
||||
heartbeat|hea-rt-be-at|health|Pulse of the heart
|
||||
exercise|ex-er-ci-se|health|Physical activity for fitness
|
||||
meditation|me-di-ta-tion|health|Practice of focused calm reflection
|
||||
relaxation|re-la-xa-tion|health|State of being free from tension
|
||||
`;
|
||||
|
||||
export const extraWords = RAW.trim()
|
||||
.split('\n')
|
||||
.map(line => line.trim())
|
||||
.filter(Boolean)
|
||||
.map(line => {
|
||||
const [word, tiles, theme, clue] = line.split('|');
|
||||
return { word, tiles: tiles.split('-'), theme, clue };
|
||||
});
|
||||
@@ -72,6 +72,13 @@ export function solveBoard(quartets, maxWords = 30) {
|
||||
const quartilesList = quartets.map(q => q.join('').toLowerCase());
|
||||
const quartileSet = new Set(quartilesList);
|
||||
|
||||
// Target quartiles are always valid, even if missing from the dictionary
|
||||
quartilesList.forEach((word, qIdx) => {
|
||||
if (!foundMap.has(word)) {
|
||||
foundMap.set(word, [qIdx * 4, qIdx * 4 + 1, qIdx * 4 + 2, qIdx * 4 + 3]);
|
||||
}
|
||||
});
|
||||
|
||||
let words = [];
|
||||
|
||||
for (const [word, path] of foundMap.entries()) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { sound } from '../engine/audio.js';
|
||||
|
||||
export function createTileGrid({ onTileSelected }) {
|
||||
export function createTileGrid({ onTileSelected, onTogglePin }) {
|
||||
const container = document.createElement('div');
|
||||
container.className = 'board-container';
|
||||
|
||||
@@ -13,15 +13,27 @@ export function createTileGrid({ onTileSelected }) {
|
||||
.map(tile => {
|
||||
const isSelected = activeSet.has(tile.id);
|
||||
const isLocked = tile.isLocked;
|
||||
const isPinned = !!tile.isPinned;
|
||||
|
||||
return `
|
||||
<button
|
||||
class="board-tile ${isSelected ? 'selected' : ''} ${isLocked ? 'locked' : ''}"
|
||||
<div
|
||||
class="board-tile ${isSelected ? 'selected' : ''} ${isLocked ? 'locked' : ''} ${isPinned ? 'pinned' : ''}"
|
||||
data-id="${tile.id}"
|
||||
aria-label="Tile ${tile.text}"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
aria-label="Tile ${tile.text}${isPinned ? ', pinned' : ''}"
|
||||
>
|
||||
${tile.text}
|
||||
</button>
|
||||
<span class="tile-letter-text">${tile.text}</span>
|
||||
<button
|
||||
type="button"
|
||||
class="tile-pin-btn ${isPinned ? 'is-pinned' : ''}"
|
||||
data-pin-id="${tile.id}"
|
||||
aria-label="${isPinned ? 'Unpin tile' : 'Pin tile in place'}"
|
||||
title="${isPinned ? 'Unpin tile (Click or right-click to pin/unpin)' : 'Pin tile to current spot (keeps it from moving on shuffle)'}"
|
||||
>
|
||||
<span class="pin-icon">${isPinned ? '📌' : '📍'}</span>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
})
|
||||
.join('')}
|
||||
@@ -29,12 +41,48 @@ export function createTileGrid({ onTileSelected }) {
|
||||
`;
|
||||
|
||||
const tiles = container.querySelectorAll('.board-tile');
|
||||
tiles.forEach(tileBtn => {
|
||||
const id = parseInt(tileBtn.getAttribute('data-id'), 10);
|
||||
tileBtn.addEventListener('click', () => {
|
||||
tiles.forEach(tileEl => {
|
||||
const id = parseInt(tileEl.getAttribute('data-id'), 10);
|
||||
|
||||
// Main tile click to add/remove from tray
|
||||
tileEl.addEventListener('click', e => {
|
||||
// If clicking pin button, don't trigger tile selection
|
||||
if (e.target.closest('.tile-pin-btn')) return;
|
||||
sound.playTileClick();
|
||||
onTileSelected(id);
|
||||
});
|
||||
|
||||
// Keyboard accessibility
|
||||
tileEl.addEventListener('keydown', e => {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
e.preventDefault();
|
||||
sound.playTileClick();
|
||||
onTileSelected(id);
|
||||
}
|
||||
});
|
||||
|
||||
// Right-click to toggle pin
|
||||
tileEl.addEventListener('contextmenu', e => {
|
||||
e.preventDefault();
|
||||
if (onTogglePin) {
|
||||
sound.playTileClick();
|
||||
onTogglePin(id);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Pin button click listener
|
||||
const pinBtns = container.querySelectorAll('.tile-pin-btn');
|
||||
pinBtns.forEach(btn => {
|
||||
const pinId = parseInt(btn.getAttribute('data-pin-id'), 10);
|
||||
btn.addEventListener('click', e => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
if (onTogglePin) {
|
||||
sound.playTileClick();
|
||||
onTogglePin(pinId);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
11955
src/data/puzzles.js
11955
src/data/puzzles.js
File diff suppressed because it is too large
Load Diff
@@ -4,22 +4,91 @@ import { solveBoard } from './solver.js';
|
||||
/**
|
||||
* Generates a random valid Quartiles puzzle from the target word pool
|
||||
*/
|
||||
/**
|
||||
* Generates a random valid Quartiles puzzle from the target word pool
|
||||
* Guarantees:
|
||||
* - 20 strictly unique tiles (no duplicates anywhere on board)
|
||||
* - All tiles are at least 2 characters (never 1 letter)
|
||||
* - Anti-repetition: tracks recently used words in localStorage across games
|
||||
* - Highly varied and random puzzles
|
||||
*/
|
||||
export function generateRandomPuzzle(seed) {
|
||||
const pool = [...TARGET_WORDS_POOL];
|
||||
// Shuffle pool
|
||||
for (let i = pool.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[pool[i], pool[j]] = [pool[j], pool[i]];
|
||||
// Load recently used target words to prevent repetition across games
|
||||
let recentWords = [];
|
||||
try {
|
||||
const rawRecent = localStorage.getItem('quartiles_recent_target_words');
|
||||
if (rawRecent) {
|
||||
recentWords = JSON.parse(rawRecent);
|
||||
if (!Array.isArray(recentWords)) recentWords = [];
|
||||
}
|
||||
} catch (e) {
|
||||
recentWords = [];
|
||||
}
|
||||
const recentSet = new Set(recentWords.map(w => w.toLowerCase()));
|
||||
|
||||
// Filter pool to prioritize words not played recently
|
||||
const nonRecentPool = TARGET_WORDS_POOL.filter(w => !recentSet.has(w.word.toLowerCase()));
|
||||
// If non-recent pool is too small, use full pool
|
||||
const poolCandidate = nonRecentPool.length >= 25 ? nonRecentPool : [...TARGET_WORDS_POOL];
|
||||
|
||||
// Helper to shuffle an array
|
||||
function shuffle(arr) {
|
||||
const a = [...arr];
|
||||
for (let i = a.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[a[i], a[j]] = [a[j], a[i]];
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
// Pick 5 words that don't repeat letters/roots too excessively
|
||||
const selectedWords = pool.slice(0, 5);
|
||||
const quartets = selectedWords.map(w => w.tiles);
|
||||
// Attempt to find 5 words with 0 tile collisions (strictly 20 unique tiles)
|
||||
let selectedWords = null;
|
||||
const attemptsPools = [shuffle(poolCandidate), shuffle(TARGET_WORDS_POOL), shuffle(TARGET_WORDS_POOL)];
|
||||
|
||||
const solved = solveBoard(quartets);
|
||||
for (const pool of attemptsPools) {
|
||||
const picked = [];
|
||||
const usedTiles = new Set();
|
||||
|
||||
for (const item of pool) {
|
||||
if (!item.tiles || item.tiles.length !== 4) continue;
|
||||
// Ensure no 1-letter tiles
|
||||
if (!item.tiles.every(t => t && t.length >= 2)) continue;
|
||||
|
||||
// Check collision with already used tiles
|
||||
const hasCollision = item.tiles.some(t => usedTiles.has(t.toLowerCase()));
|
||||
if (!hasCollision) {
|
||||
picked.push(item);
|
||||
item.tiles.forEach(t => usedTiles.add(t.toLowerCase()));
|
||||
if (picked.length === 5) {
|
||||
selectedWords = picked;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (selectedWords && selectedWords.length === 5) break;
|
||||
}
|
||||
|
||||
// Fallback if extreme constraints somehow failed
|
||||
if (!selectedWords || selectedWords.length < 5) {
|
||||
selectedWords = shuffle(TARGET_WORDS_POOL).slice(0, 5);
|
||||
}
|
||||
|
||||
// Save selected words into recent words history (keep up to last 50 words)
|
||||
try {
|
||||
const updatedRecent = [
|
||||
...selectedWords.map(w => w.word.toLowerCase()),
|
||||
...recentWords.filter(w => !selectedWords.some(sw => sw.word.toLowerCase() === w))
|
||||
].slice(0, 50);
|
||||
localStorage.setItem('quartiles_recent_target_words', JSON.stringify(updatedRecent));
|
||||
} catch (e) {
|
||||
// Non-fatal if localStorage unavailable
|
||||
}
|
||||
|
||||
const quartets = selectedWords.map(w => w.tiles.map(t => t.toLowerCase().trim()));
|
||||
const solved = solveBoard(quartets, 30);
|
||||
|
||||
const id = 'custom-' + Date.now();
|
||||
const theme = selectedWords[0].theme ? `${selectedWords[0].theme.toUpperCase()} & MORE` : 'Unlimited Challenge';
|
||||
const theme = selectedWords[0].theme ? `${selectedWords[0].theme.toUpperCase()} & BEYOND` : 'Unlimited Challenge';
|
||||
|
||||
return {
|
||||
id,
|
||||
@@ -44,12 +113,17 @@ export function generateRandomPuzzle(seed) {
|
||||
/**
|
||||
* Validates and creates a custom puzzle from user-provided quartets
|
||||
* Expects array of 5 quartets: [[t1,t2,t3,t4], [t5,t6,t7,t8], ...]
|
||||
* Enforces:
|
||||
* - Exactly 20 tiles total
|
||||
* - All 20 tiles must be unique (no duplicate tiles on board)
|
||||
* - Every tile must be at least 2 letters (no 1-letter tiles)
|
||||
*/
|
||||
export function createCustomPuzzle(quartets, customTitle = 'Custom Community Puzzle') {
|
||||
if (!Array.isArray(quartets) || quartets.length !== 5) {
|
||||
throw new Error('Puzzle must have exactly 5 quartets (4-tile words)');
|
||||
}
|
||||
|
||||
const allTiles = [];
|
||||
for (let i = 0; i < quartets.length; i++) {
|
||||
const q = quartets[i];
|
||||
if (!Array.isArray(q) || q.length !== 4) {
|
||||
@@ -57,14 +131,21 @@ export function createCustomPuzzle(quartets, customTitle = 'Custom Community Puz
|
||||
}
|
||||
for (let j = 0; j < 4; j++) {
|
||||
const tile = q[j].toLowerCase().trim();
|
||||
if (!/^[a-z]{2,4}$/.test(tile)) {
|
||||
throw new Error(`Tile "${tile}" in quartet #${i + 1} must be 2 to 4 letters`);
|
||||
if (!/^[a-z]{2,8}$/.test(tile)) {
|
||||
throw new Error(`Tile "${tile}" in quartet #${i + 1} must be at least 2 letters`);
|
||||
}
|
||||
allTiles.push(tile);
|
||||
}
|
||||
}
|
||||
|
||||
// Enforce no duplicate tiles across the board
|
||||
const uniqueTileSet = new Set(allTiles);
|
||||
if (uniqueTileSet.size !== 20) {
|
||||
throw new Error('All 20 tiles on the board must be unique. Duplicate tiles are not allowed.');
|
||||
}
|
||||
|
||||
const normalizedQuartets = quartets.map(q => q.map(t => t.toLowerCase().trim()));
|
||||
const solved = solveBoard(normalizedQuartets);
|
||||
const solved = solveBoard(normalizedQuartets, 30);
|
||||
|
||||
return {
|
||||
id: 'user-' + btoa(normalizedQuartets.map(q => q.join('-')).join('|')).slice(0, 16),
|
||||
|
||||
@@ -37,6 +37,13 @@ export function solveBoard(quartets, maxWords = 30) {
|
||||
const quartilesList = quartets.map(q => q.join('').toLowerCase());
|
||||
const quartileSet = new Set(quartilesList);
|
||||
|
||||
// Target quartiles are always valid, even if missing from the dictionary
|
||||
quartilesList.forEach((word, qIdx) => {
|
||||
if (!foundMap.has(word)) {
|
||||
foundMap.set(word, [qIdx * 4, qIdx * 4 + 1, qIdx * 4 + 2, qIdx * 4 + 3]);
|
||||
}
|
||||
});
|
||||
|
||||
let words = [];
|
||||
|
||||
for (const [word, path] of foundMap.entries()) {
|
||||
|
||||
@@ -145,6 +145,9 @@ async function initApp() {
|
||||
const tileGrid = createTileGrid({
|
||||
onTileSelected: tileId => {
|
||||
gameState.onTileClicked(tileId);
|
||||
},
|
||||
onTogglePin: tileId => {
|
||||
gameState.togglePinTile(tileId);
|
||||
}
|
||||
});
|
||||
appContainer.appendChild(tileGrid.element);
|
||||
|
||||
@@ -4,8 +4,9 @@ import { getRankInfo, QUARTILE_COMPLETION_BONUS } from '../engine/constants.js';
|
||||
class GameStateManager {
|
||||
constructor() {
|
||||
this.currentPuzzle = null;
|
||||
this.boardTiles = []; // Array of { id, text, isQuartileSolved, isLocked }
|
||||
this.boardTiles = []; // Array of { id, text, originalText, isQuartileSolved, isLocked, isPinned }
|
||||
this.activeTileIds = []; // Array of tile IDs in construction tray
|
||||
this.userPinnedTileIds = new Set(); // Set of tile IDs manually pinned by user
|
||||
this.foundWords = new Map(); // word -> wordData
|
||||
this.score = 0;
|
||||
this.quartilesBonusAwarded = false;
|
||||
@@ -48,6 +49,7 @@ class GameStateManager {
|
||||
this.currentPuzzle = puzzle;
|
||||
this.saveActivePuzzle();
|
||||
this.activeTileIds = [];
|
||||
this.userPinnedTileIds = new Set();
|
||||
this.foundWords = new Map();
|
||||
this.score = 0;
|
||||
this.quartilesBonusAwarded = false;
|
||||
@@ -60,7 +62,8 @@ class GameStateManager {
|
||||
text: text.toUpperCase(),
|
||||
originalText: text,
|
||||
isQuartileSolved: false,
|
||||
isLocked: false
|
||||
isLocked: false,
|
||||
isPinned: false
|
||||
}));
|
||||
|
||||
// Restore saved state from LocalStorage if available
|
||||
@@ -136,6 +139,8 @@ class GameStateManager {
|
||||
score: this.score,
|
||||
bonus: this.quartilesBonusAwarded,
|
||||
tileOrder: this.boardTiles.map(t => t.id),
|
||||
pinnedTileIds: Array.from(this.userPinnedTileIds),
|
||||
lockQuartiles: this.lockQuartiles,
|
||||
activeTileIds: this.activeTileIds,
|
||||
isRevealed: this.isRevealed,
|
||||
hintIndex: this.hintIndex,
|
||||
@@ -143,6 +148,11 @@ class GameStateManager {
|
||||
};
|
||||
try {
|
||||
localStorage.setItem(saveKey, JSON.stringify(payload));
|
||||
// Maintain persistent list of all played puzzle IDs
|
||||
const rawAll = localStorage.getItem('quartiles_all_saved_puzzle_ids');
|
||||
const allSaved = new Set(rawAll ? JSON.parse(rawAll) : []);
|
||||
allSaved.add(this.currentPuzzle.id);
|
||||
localStorage.setItem('quartiles_all_saved_puzzle_ids', JSON.stringify(Array.from(allSaved)));
|
||||
} catch (err) {
|
||||
console.warn('LocalStorage save failed:', err);
|
||||
}
|
||||
@@ -182,9 +192,16 @@ class GameStateManager {
|
||||
}
|
||||
this.isRevealed = !!parsed.isRevealed;
|
||||
this.hintIndex = parsed.hintIndex || 0;
|
||||
if (parsed.lockQuartiles !== undefined) {
|
||||
this.lockQuartiles = parsed.lockQuartiles;
|
||||
}
|
||||
|
||||
// Re-mark solved quartiles
|
||||
this.updateSolvedQuartileTiles();
|
||||
// Restore pinned tiles
|
||||
if (Array.isArray(parsed.pinnedTileIds)) {
|
||||
this.userPinnedTileIds = new Set(parsed.pinnedTileIds.filter(id => id >= 0 && id < 20));
|
||||
} else {
|
||||
this.userPinnedTileIds = new Set();
|
||||
}
|
||||
|
||||
// Restore active tray tiles if any
|
||||
if (Array.isArray(parsed.activeTileIds)) {
|
||||
@@ -194,16 +211,18 @@ class GameStateManager {
|
||||
// Restore tile order if saved
|
||||
if (Array.isArray(parsed.tileOrder) && parsed.tileOrder.length === 20) {
|
||||
const isSequential = parsed.tileOrder.every((id, idx) => id === idx);
|
||||
if (!isSequential || this.foundWords.size > 0) {
|
||||
if (!isSequential || this.foundWords.size > 0 || this.userPinnedTileIds.size > 0) {
|
||||
const tileMap = new Map(this.boardTiles.map(t => [t.id, t]));
|
||||
const reordered = parsed.tileOrder.map(id => tileMap.get(id)).filter(Boolean);
|
||||
if (reordered.length === 20) {
|
||||
this.boardTiles = reordered;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.foundWords.size > 0;
|
||||
|
||||
// Re-mark solved quartiles and user-pinned tiles
|
||||
this.updateSolvedQuartileTiles();
|
||||
return this.foundWords.size > 0 || this.userPinnedTileIds.size > 0;
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -212,7 +231,7 @@ class GameStateManager {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if a tile belongs to an already found Quartile
|
||||
// Check if a tile belongs to an already found Quartile or is user-pinned
|
||||
updateSolvedQuartileTiles() {
|
||||
const solvedQuartileWords = new Set();
|
||||
for (const [w, data] of this.foundWords.entries()) {
|
||||
@@ -221,10 +240,11 @@ class GameStateManager {
|
||||
}
|
||||
}
|
||||
|
||||
// For each target quartet, check if solved
|
||||
// Initialize all tiles with their pin state
|
||||
this.boardTiles.forEach(tile => {
|
||||
tile.isQuartileSolved = false;
|
||||
tile.isLocked = false;
|
||||
tile.isPinned = this.userPinnedTileIds.has(tile.id);
|
||||
tile.isLocked = tile.isPinned;
|
||||
});
|
||||
|
||||
for (let qIdx = 0; qIdx < this.currentPuzzle.quartets.length; qIdx++) {
|
||||
@@ -237,7 +257,7 @@ class GameStateManager {
|
||||
const tile = this.boardTiles.find(t => t.id === i);
|
||||
if (tile) {
|
||||
tile.isQuartileSolved = true;
|
||||
if (this.lockQuartiles) {
|
||||
if (this.lockQuartiles || tile.isPinned) {
|
||||
tile.isLocked = true;
|
||||
}
|
||||
}
|
||||
@@ -246,6 +266,25 @@ class GameStateManager {
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle user pin on an individual tile
|
||||
togglePinTile(tileId) {
|
||||
if (this.userPinnedTileIds.has(tileId)) {
|
||||
this.userPinnedTileIds.delete(tileId);
|
||||
} else {
|
||||
this.userPinnedTileIds.add(tileId);
|
||||
}
|
||||
this.updateSolvedQuartileTiles();
|
||||
this.saveProgress();
|
||||
this.notify();
|
||||
const tile = this.boardTiles.find(t => t.id === tileId);
|
||||
const isPinned = this.userPinnedTileIds.has(tileId);
|
||||
this.notifyToast(
|
||||
isPinned ? `📌 Pinned tile "${tile?.text || ''}" in place` : `🔓 Unpinned tile "${tile?.text || ''}"`,
|
||||
'info',
|
||||
1600
|
||||
);
|
||||
}
|
||||
|
||||
// Reorganizes the board: locked solved quartiles go to top rows
|
||||
reorganizeBoard() {
|
||||
this.updateSolvedQuartileTiles();
|
||||
@@ -347,30 +386,56 @@ class GameStateManager {
|
||||
}
|
||||
}
|
||||
|
||||
// Shuffle unlocked tiles
|
||||
// Shuffle unlocked & unpinned tiles
|
||||
shuffle() {
|
||||
const lockedTiles = this.lockQuartiles ? this.boardTiles.filter(t => t.isLocked) : [];
|
||||
const unlockedTiles = this.lockQuartiles ? this.boardTiles.filter(t => !t.isLocked) : [...this.boardTiles];
|
||||
const unpinnedPositions = [];
|
||||
const unpinnedTiles = [];
|
||||
|
||||
this.boardTiles.forEach((tile, idx) => {
|
||||
const isFixed = tile.isPinned || (this.lockQuartiles && tile.isLocked);
|
||||
if (!isFixed) {
|
||||
unpinnedPositions.push(idx);
|
||||
unpinnedTiles.push(tile);
|
||||
}
|
||||
});
|
||||
|
||||
// Fisher-Yates shuffle
|
||||
for (let i = unlockedTiles.length - 1; i > 0; i--) {
|
||||
for (let i = unpinnedTiles.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[unlockedTiles[i], unlockedTiles[j]] = [unlockedTiles[j], unlockedTiles[i]];
|
||||
[unpinnedTiles[i], unpinnedTiles[j]] = [unpinnedTiles[j], unpinnedTiles[i]];
|
||||
}
|
||||
|
||||
this.boardTiles = [...lockedTiles, ...unlockedTiles];
|
||||
const newBoard = [...this.boardTiles];
|
||||
unpinnedPositions.forEach((pos, idx) => {
|
||||
newBoard[pos] = unpinnedTiles[idx];
|
||||
});
|
||||
|
||||
this.boardTiles = newBoard;
|
||||
this.saveProgress();
|
||||
this.notify();
|
||||
}
|
||||
|
||||
// Sort unlocked tiles alphabetically
|
||||
// Sort unlocked & unpinned tiles alphabetically
|
||||
sortAlphabetical() {
|
||||
const lockedTiles = this.lockQuartiles ? this.boardTiles.filter(t => t.isLocked) : [];
|
||||
const unlockedTiles = this.lockQuartiles ? this.boardTiles.filter(t => !t.isLocked) : [...this.boardTiles];
|
||||
const unpinnedPositions = [];
|
||||
const unpinnedTiles = [];
|
||||
|
||||
unlockedTiles.sort((a, b) => a.text.localeCompare(b.text));
|
||||
this.boardTiles.forEach((tile, idx) => {
|
||||
const isFixed = tile.isPinned || (this.lockQuartiles && tile.isLocked);
|
||||
if (!isFixed) {
|
||||
unpinnedPositions.push(idx);
|
||||
unpinnedTiles.push(tile);
|
||||
}
|
||||
});
|
||||
|
||||
this.boardTiles = [...lockedTiles, ...unlockedTiles];
|
||||
unpinnedTiles.sort((a, b) => a.text.localeCompare(b.text));
|
||||
|
||||
const newBoard = [...this.boardTiles];
|
||||
unpinnedPositions.forEach((pos, idx) => {
|
||||
newBoard[pos] = unpinnedTiles[idx];
|
||||
});
|
||||
|
||||
this.boardTiles = newBoard;
|
||||
this.saveProgress();
|
||||
this.notify();
|
||||
}
|
||||
@@ -385,13 +450,16 @@ class GameStateManager {
|
||||
const constructedWord = this.activeTileIds
|
||||
.map(id => {
|
||||
const tile = this.boardTiles.find(t => t.id === id);
|
||||
return tile ? tile.text.toLowerCase() : '';
|
||||
return tile ? tile.text.toLowerCase().trim() : '';
|
||||
})
|
||||
.join('');
|
||||
|
||||
// Check if already found
|
||||
if (this.foundWords.has(constructedWord)) {
|
||||
this.notifyToast(`"${constructedWord.toUpperCase()}" already found!`, 'warning');
|
||||
this.activeTileIds = [];
|
||||
this.saveProgress();
|
||||
this.notify();
|
||||
return { success: false, reason: 'duplicate', word: constructedWord };
|
||||
}
|
||||
|
||||
|
||||
@@ -338,6 +338,46 @@
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
/* User-pinned tile state */
|
||||
.board-tile.pinned {
|
||||
border-color: #f59e0b !important;
|
||||
box-shadow: 0 0 0 1.5px rgba(245, 158, 11, 0.45), var(--tile-shadow) !important;
|
||||
}
|
||||
|
||||
.tile-pin-btn {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
right: 2px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: transparent;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
border-radius: 4px;
|
||||
opacity: 0.22;
|
||||
transition: opacity var(--transition-fast), transform var(--transition-fast);
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.board-tile:hover .tile-pin-btn,
|
||||
.tile-pin-btn.is-pinned {
|
||||
opacity: 0.95;
|
||||
}
|
||||
|
||||
.tile-pin-btn .pin-icon {
|
||||
font-size: 0.7rem;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.tile-pin-btn.is-pinned {
|
||||
transform: scale(1.12);
|
||||
filter: drop-shadow(0 1px 2px rgba(245, 158, 11, 0.4));
|
||||
}
|
||||
|
||||
/* Board tile shuffle animation */
|
||||
.board-tile.flipping {
|
||||
animation: tileFlip 0.4s var(--ease-smooth);
|
||||
|
||||
Reference in New Issue
Block a user