document.addEventListener('DOMContentLoaded', () => { // --- Get Elements --- const gridContainer = document.getElementById('grid-container'); const targetCoordsDisplay = document.getElementById('target-coords'); const feedbackDisplay = document.getElementById('feedback'); const itemNameDisplay = document.getElementById('item-name'); const yAxisLabelsContainer = document.getElementById('y-axis-labels'); const xAxisLabelsContainer = document.getElementById('x-axis-labels'); const xAxisContainer = document.getElementById('x-axis-container'); const scoreDisplay = document.getElementById('score-display'); // --- Game Settings --- const gridSize = 8; const cellSize = 40; // Pixels // --- Items to Find --- const itemsToFind = [ { name: "a sparkling diamond", emoji: "💎" }, { name: "a red apple", emoji: "🍎" }, { name: "a yummy pizza slice", emoji: "🍕" }, { name: "a fast rocket", emoji: "🚀" }, { name: "a cute puppy", emoji: "🐶" }, { name: "a bright star", emoji: "⭐" }, { name: "a cool robot", emoji: "🤖" }, { name: "a friendly ghost", emoji: "👻" }, { name: "a birthday cake", emoji: "🎂" }, { name: "a magical unicorn", emoji: "🦄" } ]; const totalItems = itemsToFind.length; // --- Game State --- let targetX = -1; let targetY = -1; let currentItemIndex = 0; let foundCurrent = false; let score = 0; // --- Initialize Grid and Axes --- function initializeGameArea() { gridContainer.innerHTML = ''; xAxisLabelsContainer.innerHTML = ''; yAxisLabelsContainer.innerHTML = ''; score = 0; currentItemIndex = 0; updateScoreDisplay(); // CSS variable for reference if needed, though direct style is used now document.documentElement.style.setProperty('--cell-size', `${cellSize}px`); const gridTotalSize = gridSize * cellSize; const yAxisWidth = 20; // Must match CSS .y-axis-label width const yAxisMargin = 5; // Must match CSS #y-axis-labels margin-right // --- Configure Grid Container Styles Explicitly --- gridContainer.style.width = `${gridTotalSize}px`; gridContainer.style.height = `${gridTotalSize}px`; gridContainer.style.display = 'grid'; // **Ensure grid layout** gridContainer.style.gridTemplateColumns = `repeat(${gridSize}, ${cellSize}px)`; // **Ensure columns** gridContainer.style.gridTemplateRows = `repeat(${gridSize}, ${cellSize}px)`; // **Ensure rows** // --- // Configure Axis Containers yAxisLabelsContainer.style.height = `${gridTotalSize}px`; // Match grid height xAxisLabelsContainer.style.width = `${gridTotalSize}px`; // Inner label container matches grid width xAxisContainer.style.width = `${yAxisWidth + yAxisMargin + gridTotalSize}px`; // Outer width includes Y-axis space xAxisLabelsContainer.style.marginLeft = `${yAxisWidth + yAxisMargin}px`; // Align labels under grid // Create Y-axis labels (1 to N, bottom-up visually) for (let y = 1; y <= gridSize; y++) { const label = document.createElement('div'); label.classList.add('axis-label', 'y-axis-label'); label.textContent = y; label.style.height = `${cellSize}px`; yAxisLabelsContainer.appendChild(label); } // Create X-axis labels (1 to N, left-to-right) for (let x = 1; x <= gridSize; x++) { const label = document.createElement('div'); label.classList.add('axis-label', 'x-axis-label'); label.textContent = x; label.style.width = `${cellSize}px`; xAxisLabelsContainer.appendChild(label); } // Create grid cells // Loop Y from gridSize down to 1 so that Y=1 is the bottom row visually for (let y = gridSize; y >= 1; y--) { // Loop X from 1 to gridSize as usual (left-to-right) for (let x = 1; x <= gridSize; x++) { const cell = document.createElement('div'); cell.classList.add('grid-cell'); cell.dataset.x = x; // Store correct X coordinate cell.dataset.y = y; // Store correct Y coordinate cell.style.width = `${cellSize}px`; // Explicit size cell.style.height = `${cellSize}px`; // Explicit size cell.addEventListener('click', handleCellClick); gridContainer.appendChild(cell); } } console.log("Grid, Axes, and Score Initialized."); } // --- Update Score Display --- function updateScoreDisplay() { scoreDisplay.textContent = `Score: ${score} / ${totalItems}`; } // --- Set a New Target Item and Location --- function setNewTarget() { foundCurrent = false; // --- Game Over Check --- if (currentItemIndex >= totalItems) { let finalMessage = `All done! Your final score: ${score} / ${totalItems}! 🎉`; if (score === totalItems) { finalMessage += " Perfect score! 🥳"; } else if (score >= totalItems / 2) { finalMessage += " Great job! 👍"; } feedbackDisplay.textContent = finalMessage; feedbackDisplay.className = 'correct-feedback'; targetCoordsDisplay.textContent = "(✔,✔)"; itemNameDisplay.textContent = 'all the items'; // Optional: Add a visible reset button here instead of forcing refresh return; } const currentItem = itemsToFind[currentItemIndex]; // --- Find Empty Cell for New Target --- let newTargetFound = false; let attempts = 0; // Prevent infinite loop const maxAttempts = gridSize * gridSize * 2; // Generous limit while (!newTargetFound && attempts < maxAttempts) { targetX = Math.floor(Math.random() * gridSize) + 1; targetY = Math.floor(Math.random() * gridSize) + 1; const potentialCell = gridContainer.querySelector(`.grid-cell[data-x="${targetX}"][data-y="${targetY}"]`); // Check if the cell exists AND is visually empty (no emoji) if (potentialCell && potentialCell.textContent.trim() === '') { newTargetFound = true; } attempts++; } // Handle unlikely case where no empty cell is found if (!newTargetFound) { console.error("Could not find an empty cell for the next target!"); feedbackDisplay.textContent = "Uh oh, the map is full! Please refresh."; return; } // --- Update Display --- itemNameDisplay.textContent = currentItem.name; targetCoordsDisplay.textContent = `(${targetX}, ${targetY})`; feedbackDisplay.textContent = `Where is ${currentItem.name}? (${currentItemIndex + 1}/${totalItems})`; feedbackDisplay.className = ''; // Reset temporary styles from previous round document.querySelectorAll('.grid-cell').forEach(cell => { cell.classList.remove('just-found', 'incorrect'); }); console.log(`Round ${currentItemIndex + 1}: Find ${currentItem.name} at (${targetX}, ${targetY})`); } // --- Handle Cell Click --- function handleCellClick(event) { // Prevent action if round/game is over or cell already found if (foundCurrent || currentItemIndex >= totalItems) return; const clickedCell = event.target; if (clickedCell.classList.contains('found-item')) return; const clickedX = parseInt(clickedCell.dataset.x); const clickedY = parseInt(clickedCell.dataset.y); // Clear any lingering incorrect styles document.querySelectorAll('.grid-cell.incorrect').forEach(cell => { cell.classList.remove('incorrect'); }); // --- Check if Correct --- if (clickedX === targetX && clickedY === targetY) { foundCurrent = true; score++; updateScoreDisplay(); const currentItem = itemsToFind[currentItemIndex]; feedbackDisplay.textContent = `You found ${currentItem.name}! 👍`; feedbackDisplay.className = 'correct-feedback'; clickedCell.textContent = currentItem.emoji; // Add emoji clickedCell.classList.add('just-found'); // Temporary highlight // After highlight animation, switch to permanent 'found' style setTimeout(() => { clickedCell.classList.remove('just-found'); clickedCell.classList.add('found-item'); }, 600); // Duration should be >= pulse animation time currentItemIndex++; // Move to next item setTimeout(setNewTarget, 1800); // Delay before next target } else { // --- Incorrect Guess --- feedbackDisplay.textContent = "Not quite! Try again. 🤔"; feedbackDisplay.className = 'incorrect-feedback'; clickedCell.classList.add('incorrect'); // Remove incorrect style after shake animation setTimeout(() => { // Check if still marked incorrect (user might click fast) if (clickedCell.classList.contains('incorrect')) { clickedCell.classList.remove('incorrect'); } }, 500); // Match shake animation duration } } // --- Start the Game --- initializeGameArea(); setNewTarget(); }); // End DOMContentLoaded