File size: 9,571 Bytes
dbdfa02 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 |
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 |