document.addEventListener('DOMContentLoaded', () => { const scoreDisplay = document.getElementById('score'); const totalQuestionsDisplay = document.getElementById('total-questions'); const num1Display = document.getElementById('num1'); const num2Display = document.getElementById('num2'); const feedbackArea = document.getElementById('feedback-area'); const fieldChoicesContainer = document.getElementById('field-choices'); const OPTIONS_COUNT = 3; // Number of plot choices (1 correct, 2 incorrect) const MAX_FACTOR = 6; // Maximum number for factors (e.g., up to 6x6) const TOTAL_ROUNDS = 10; // Number of questions in a game // --- Items for the Farm --- const farmItems = ['🍎', '🥕', '🐔', '🐑', '🌻', '🌽']; // --- Generate Multiplication Problems --- let possibleProblems = []; function generateProblems() { possibleProblems = []; for (let i = 1; i <= MAX_FACTOR; i++) { // Start j from 1 to include squares and both orders (e.g., 2x3 and 3x2 are distinct visual arrays) for (let j = 1; j <= MAX_FACTOR; j++) { possibleProblems.push({ num1: i, num2: j, answer: i * j }); } } // Remove duplicates might be needed if we consider A*B same as B*A later } // --- Game State --- let score = 0; let currentProblem = null; let currentRound = 0; let waitingForNext = false; // --- Utility: Get Random Int --- function getRandomInt(max) { return Math.floor(Math.random() * max); } // --- Utility: Shuffle Array --- function shuffleArray(array) { for (let i = array.length - 1; i > 0; i--) { const j = getRandomInt(i + 1); [array[i], array[j]] = [array[j], array[i]]; } } // --- Setup a New Round --- function setupNewRound() { if (currentRound >= TOTAL_ROUNDS) { endGame(); return; } waitingForNext = false; fieldChoicesContainer.innerHTML = ''; feedbackArea.textContent = "Click the farm plot that matches the problem!"; feedbackArea.className = ''; currentRound++; // 1. Choose a target problem if (!possibleProblems || possibleProblems.length === 0) generateProblems(); // Regenerate if empty const problemIndex = getRandomInt(possibleProblems.length); currentProblem = possibleProblems.splice(problemIndex, 1)[0]; // Pick and remove num1Display.textContent = currentProblem.num1; num2Display.textContent = currentProblem.num2; // 2. Create options array (as {rows, cols}) // Allow commutative property visually (3x4 can be 3 rows of 4 OR 4 rows of 3) const correctOption = { rows: currentProblem.num1, cols: currentProblem.num2 }; const options = [correctOption]; // 3. Generate incorrect options while (options.length < OPTIONS_COUNT) { let wrongRows, wrongCols; let isDuplicate = true; let attempts = 0; // Prevent infinite loop while(isDuplicate && attempts < 20) { // Generate wrong dimensions, make sure at least one is different const changeRows = Math.random() > 0.5; wrongRows = changeRows ? getRandomInt(MAX_FACTOR) + 1 : correctOption.rows; wrongCols = !changeRows ? getRandomInt(MAX_FACTOR) + 1 : correctOption.cols; // Ensure it's actually wrong AND not zero product AND different from target if((wrongRows !== correctOption.rows || wrongCols !== correctOption.cols) && (wrongRows * wrongCols > 0) ) { // Check if this combination (or its commutative pair) is already in options isDuplicate = options.some(opt => (opt.rows === wrongRows && opt.cols === wrongCols) || (opt.rows === wrongCols && opt.cols === wrongRows) ); } else { isDuplicate = true; // Force retry if generated same as correct or zero product } attempts++; } // If stuck finding unique, just create a simple wrong one if (attempts >= 20) { wrongRows = correctOption.rows === 1 ? 2 : correctOption.rows -1; wrongCols = correctOption.cols; isDuplicate = options.some(opt => (opt.rows === wrongRows && opt.cols === wrongCols) || (opt.rows === wrongCols && opt.cols === wrongRows) ); // Final check } if (!isDuplicate) { options.push({ rows: wrongRows, cols: wrongCols }); } } // 4. Shuffle options shuffleArray(options); // 5. Create and display field elements options.forEach(plot => { const fieldDiv = document.createElement('div'); fieldDiv.classList.add('field-option'); fieldDiv.dataset.rows = plot.rows; fieldDiv.dataset.cols = plot.cols; // Style the grid layout for items *inside* this field fieldDiv.style.gridTemplateColumns = `repeat(${plot.cols}, auto)`; // auto size columns fieldDiv.style.gridTemplateRows = `repeat(${plot.rows}, auto)`; // auto size rows // Set a max-width to prevent huge single rows/columns fieldDiv.style.maxWidth = `${plot.cols * 35}px`; // Approx item size + gap // Add items (emoji) const itemEmoji = farmItems[getRandomInt(farmItems.length)]; for (let i = 0; i < plot.rows * plot.cols; i++) { const itemSpan = document.createElement('span'); itemSpan.classList.add('item'); itemSpan.textContent = itemEmoji; fieldDiv.appendChild(itemSpan); } fieldDiv.addEventListener('click', handleChoiceClick); fieldChoicesContainer.appendChild(fieldDiv); }); console.log("New round setup. Target:", currentProblem); } // --- Handle Field Choice Click --- function handleChoiceClick(event) { if (waitingForNext) return; const clickedField = event.currentTarget; const clickedRows = parseInt(clickedField.dataset.rows); const clickedCols = parseInt(clickedField.dataset.cols); waitingForNext = true; // Remove listeners document.querySelectorAll('.field-option').forEach(opt => { const clone = opt.cloneNode(true); opt.parentNode.replaceChild(clone, opt); }); // Check if correct (allow commutative: A x B or B x A) const isCorrect = (clickedRows === currentProblem.num1 && clickedCols === currentProblem.num2) || (clickedRows === currentProblem.num2 && clickedCols === currentProblem.num1); if (isCorrect) { score++; scoreDisplay.textContent = score; feedbackArea.textContent = `Yes! ${currentProblem.num1} x ${currentProblem.num2} = ${currentProblem.answer}! 🎉`; feedbackArea.className = 'correct-feedback'; const newClickedElement = fieldChoicesContainer.querySelector(`.field-option[data-rows="${clickedRows}"][data-cols="${clickedCols}"]`); if (newClickedElement) newClickedElement.classList.add('correct-choice'); } else { feedbackArea.textContent = `Oops! That shows ${clickedRows} x ${clickedCols}. The answer was ${currentProblem.answer}. 🤔`; feedbackArea.className = 'incorrect-feedback'; const newClickedElement = fieldChoicesContainer.querySelector(`.field-option[data-rows="${clickedRows}"][data-cols="${clickedCols}"]`); if (newClickedElement) newClickedElement.classList.add('incorrect-choice'); // Highlight the correct answer(s) setTimeout(() => { const correctElement1 = fieldChoicesContainer.querySelector(`.field-option[data-rows="${currentProblem.num1}"][data-cols="${currentProblem.num2}"]`); if (correctElement1) correctElement1.classList.add('correct-choice'); // Also highlight commutative pair if it exists and is different const correctElement2 = fieldChoicesContainer.querySelector(`.field-option[data-rows="${currentProblem.num2}"][data-cols="${currentProblem.num1}"]`); if (correctElement2 && correctElement1 !== correctElement2) correctElement2.classList.add('correct-choice'); }, 300); } // Load next round setTimeout(setupNewRound, 2500); // Longer delay to see feedback/answer } // --- End Game --- function endGame() { feedbackArea.textContent = `Game Over! Your final score: ${score} / ${TOTAL_ROUNDS}! Great work! 🥳`; feedbackArea.className = 'correct-feedback'; // Use correct style for positive end fieldChoicesContainer.innerHTML = '
Refresh the page to play again!
'; // Clear options // Optionally disable further interaction if needed } // --- Initial Game Start --- totalQuestionsDisplay.textContent = TOTAL_ROUNDS; // Set total rounds display generateProblems(); // Create the initial list of problems setupNewRound(); }); // End DOMContentLoaded