Pp's picture
Upload 3 files
dbdfa02 verified
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 = '<p style="font-size:1.2em; color: #795548;">Refresh the page to play again!</p>'; // 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