/* ====================== SCRIPT.JS - Working Word Search Game with HINT button ====================== */ /* ---------- Data: words & stories ---------- */ const data = { farm: { 3: { words: ["COW", "HEN", "BARN", "MILK", "EGGS"], storyTitle: "Maya and the Friendly Cow", story: "Maya went to the barn. She saw a cow and a hen. The hen gave eggs. Maya drank warm milk and smiled." }, 4: { words: ["FARMER", "TRACTOR", "FIELD", "CORN", "SHEEP"], storyTitle: "The Busy Farmer", story: "The farmer drove the tractor to the field. The sheep grazed while the farmer planted corn. Everyone helped in the barn." } } }; /* ---------- Global Variables ---------- */ let gridSize = 14; let grid = []; let placements = []; let wordsToFind = []; let foundWords = new Set(); let selecting = false; let selectedCells = []; const gridEl = document.getElementById('grid'); const wordListEl = document.getElementById('wordList'); const progressEl = document.getElementById('progress'); const overlay = document.getElementById('overlay'); const storyText = document.getElementById('storyText'); const storyTitle = document.getElementById('storyTitle'); /* ---------- Helper: random letter ---------- */ function randLetter() { const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; return letters[Math.floor(Math.random() * letters.length)]; } /* ---------- Grid Setup ---------- */ function makeEmptyGrid(size) { grid = Array(size).fill(null).map(() => Array(size).fill("")); } function placeWord(word, size) { const dirs = [ [1, 0], [0, 1], [1, 1], [-1, 1] ]; for (let tries = 0; tries < 200; tries++) { const dir = dirs[Math.floor(Math.random() * dirs.length)]; const row = Math.floor(Math.random() * size); const col = Math.floor(Math.random() * size); let r = row, c = col, ok = true; for (let ch of word) { if (r < 0 || r >= size || c < 0 || c >= size || (grid[r][c] && grid[r][c] !== ch)) { ok = false; break; } r += dir[0]; c += dir[1]; } if (!ok) continue; r = row; c = col; for (let ch of word) { grid[r][c] = ch; r += dir[0]; c += dir[1]; } placements.push({ word, row, col, dir }); return true; } return false; } function fillRandom(size) { for (let r = 0; r < size; r++) { for (let c = 0; c < size; c++) { if (!grid[r][c]) grid[r][c] = randLetter(); } } } function renderGrid(size) { gridEl.style.gridTemplateColumns = `repeat(${size}, 1fr)`; gridEl.innerHTML = ""; for (let r = 0; r < size; r++) { for (let c = 0; c < size; c++) { const cell = document.createElement("div"); cell.className = "cell"; cell.textContent = grid[r][c]; cell.dataset.row = r; cell.dataset.col = c; gridEl.appendChild(cell); } } } /* ---------- Word List UI ---------- */ function updateWordListUI() { wordListEl.innerHTML = ""; wordsToFind.forEach(w => { const el = document.createElement("div"); el.className = "worditem"; el.textContent = w; if (foundWords.has(w)) el.classList.add("done"); wordListEl.appendChild(el); }); progressEl.textContent = `${foundWords.size} / ${wordsToFind.length}`; } /* ---------- Selection Handling ---------- */ function attachSelectionHandlers() { gridEl.addEventListener("mousedown", e => { if (!e.target.classList.contains("cell")) return; selecting = true; selectedCells = [e.target]; e.target.classList.add("sel"); }); gridEl.addEventListener("mouseover", e => { if (!selecting || !e.target.classList.contains("cell")) return; if (!selectedCells.includes(e.target)) { selectedCells.push(e.target); e.target.classList.add("sel"); } }); document.addEventListener("mouseup", () => { if (!selecting) return; finalizeSelection(); selecting = false; }); } function finalizeSelection() { const letters = selectedCells.map(c => c.textContent).join(""); const reverse = [...letters].reverse().join(""); const match = wordsToFind.find(w => w === letters || w === reverse); if (match && !foundWords.has(match)) { foundWords.add(match); selectedCells.forEach(c => c.classList.add("found")); updateWordListUI(); if (foundWords.size === wordsToFind.length) { revealStory(); } } selectedCells.forEach(c => c.classList.remove("sel")); selectedCells = []; } /* ---------- Story Popup ---------- */ function revealStory() { overlay.classList.add("show"); storyTitle.textContent = currentStory.storyTitle; storyText.textContent = currentStory.story; } function closeStory() { overlay.classList.remove("show"); } /* ---------- Hint Feature ---------- */ function giveHint() { // Get words that are not yet found const remaining = wordsToFind.filter(w => !foundWords.has(w)); if (remaining.length === 0) return; const hintWord = remaining[Math.floor(Math.random() * remaining.length)]; const placement = placements.find(p => p.word === hintWord); if (!placement) return; // Highlight cells temporarily let r = placement.row, c = placement.col; const cells = []; for (let ch of placement.word) { const cell = [...gridEl.children].find( el => parseInt(el.dataset.row) === r && parseInt(el.dataset.col) === c ); if (cell) { cell.classList.add("sel"); cells.push(cell); } r += placement.dir[0]; c += placement.dir[1]; } // Remove highlight after 1 second setTimeout(() => { cells.forEach(cell => cell.classList.remove("sel")); }, 1000); } /* ---------- Game Init ---------- */ let currentStory; function generate() { gridSize = parseInt(document.getElementById("sizeSelect").value) || 14; const grade = parseInt(document.getElementById("gradeSelect").value); const theme = document.getElementById("themeSelect").value; const storyObj = data[theme]?.[grade]; if (!storyObj) { alert("No story data for this grade & theme!"); return; } currentStory = storyObj; wordsToFind = storyObj.words; foundWords.clear(); placements = []; makeEmptyGrid(gridSize); wordsToFind.forEach(w => placeWord(w, gridSize)); fillRandom(gridSize); renderGrid(gridSize); updateWordListUI(); } /* ---------- Button Events ---------- */ document.getElementById('newBtn').addEventListener('click', generate); document.getElementById('hintBtn').addEventListener('click', giveHint); document.getElementById('closeStory').addEventListener('click', closeStory); document.getElementById('againBtn').addEventListener('click', () => { closeStory(); generate(); }); /* ---------- Init ---------- */ attachSelectionHandlers(); generate();