document.addEventListener('DOMContentLoaded', () => { const scoreDisplay = document.getElementById('score'); const numeratorDisplay = document.querySelector('#fraction-order .numerator'); const denominatorDisplay = document.querySelector('#fraction-order .denominator'); const feedbackArea = document.getElementById('feedback-area'); const pizzaChoicesContainer = document.getElementById('pizza-choices'); const PIZZA_SIZE = 140; // Diameter of the pizza canvas const OPTIONS_COUNT = 3; // Number of pizza choices to show (1 correct, 2 incorrect) // --- Define Possible Fractions --- // Start simple, can add more complex ones later const possibleFractions = [ // Denominator 2 { num: 1, den: 2 }, // Denominator 3 { num: 1, den: 3 }, { num: 2, den: 3 }, // Denominator 4 { num: 1, den: 4 }, { num: 2, den: 4 }, { num: 3, den: 4 }, // Denominator 6 { num: 1, den: 6 }, { num: 2, den: 6 }, { num: 3, den: 6 }, { num: 4, den: 6 }, { num: 5, den: 6 }, // Denominator 8 { num: 1, den: 8 }, { num: 2, den: 8 }, { num: 3, den: 8 }, { num: 4, den: 8 }, { num: 5, den: 8 }, { num: 6, den: 8 }, { num: 7, den: 8 }, ]; // --- Game State --- let score = 0; let currentOrder = null; // Will hold {num, den} of the target fraction let waitingForNext = false; // Flag to prevent clicks during feedback/delay // --- 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]]; // Swap elements } } // --- Canvas Drawing Function --- function drawPizza(canvas, num, den) { const ctx = canvas.getContext('2d'); const radius = canvas.width / 2; const centerX = radius; const centerY = radius; const sliceAngle = (Math.PI * 2) / den; // Colors const crustColor = '#f4a460'; // Sandy brown const sauceColor = '#ff6347'; // Tomato red const cheeseColor = '#fffacd'; // Lemon chiffon (looks like cheese) ctx.clearRect(0, 0, canvas.width, canvas.height); // Draw base crust slightly larger ctx.fillStyle = crustColor; ctx.beginPath(); ctx.arc(centerX, centerY, radius, 0, Math.PI * 2); ctx.fill(); // Draw cheese base smaller than crust ctx.fillStyle = cheeseColor; ctx.beginPath(); ctx.arc(centerX, centerY, radius * 0.95, 0, Math.PI * 2); ctx.fill(); // Draw highlighted slices (sauce/toppings) ctx.fillStyle = sauceColor; for (let i = 0; i < num; i++) { const startAngle = i * sliceAngle - Math.PI / 2; // Start from top const endAngle = (i + 1) * sliceAngle - Math.PI / 2; ctx.beginPath(); ctx.moveTo(centerX, centerY); ctx.arc(centerX, centerY, radius * 0.95, startAngle, endAngle); // Fill up to cheese edge ctx.closePath(); ctx.fill(); } // Draw slice lines on top ctx.strokeStyle = crustColor; // Darker lines for contrast ctx.lineWidth = 2; for (let i = 0; i < den; i++) { const angle = i * sliceAngle - Math.PI / 2; ctx.beginPath(); ctx.moveTo(centerX, centerY); ctx.lineTo(centerX + radius * 0.95 * Math.cos(angle), centerY + radius * 0.95 * Math.sin(angle)); ctx.stroke(); } } // --- Setup a New Round --- function setupNewRound() { waitingForNext = false; pizzaChoicesContainer.innerHTML = ''; // Clear previous pizzas feedbackArea.textContent = "Click the pizza that matches the order!"; feedbackArea.className = ''; // Reset feedback style // 1. Choose a target fraction currentOrder = possibleFractions[getRandomInt(possibleFractions.length)]; numeratorDisplay.textContent = currentOrder.num; denominatorDisplay.textContent = currentOrder.den; // 2. Create options array, starting with the correct one const options = [{ num: currentOrder.num, den: currentOrder.den }]; // 3. Generate incorrect options while (options.length < OPTIONS_COUNT) { const randomFraction = possibleFractions[getRandomInt(possibleFractions.length)]; // Make sure it's not the same as the target OR already in the options const isDuplicate = options.some(opt => opt.num === randomFraction.num && opt.den === randomFraction.den); if (!isDuplicate) { options.push(randomFraction); } // Basic protection against infinite loop if somehow options are very limited if(options.length < OPTIONS_COUNT && possibleFractions.length <= options.length){ console.warn("Not enough unique fractions to generate distractors. Reusing."); // Add a non-duplicate if possible, otherwise just add another random one let foundNew = false; for(let frac of possibleFractions){ if(!options.some(opt => opt.num === frac.num && opt.den === frac.den)){ options.push(frac); foundNew = true; break; } } if(!foundNew && options.length < OPTIONS_COUNT) options.push(randomFraction); // Add duplicate if absolutely needed } } // 4. Shuffle options shuffleArray(options); // 5. Create and display pizza elements options.forEach(fraction => { const optionDiv = document.createElement('div'); optionDiv.classList.add('pizza-option'); optionDiv.dataset.num = fraction.num; optionDiv.dataset.den = fraction.den; const canvas = document.createElement('canvas'); canvas.classList.add('pizza-canvas'); canvas.width = PIZZA_SIZE; canvas.height = PIZZA_SIZE; optionDiv.appendChild(canvas); pizzaChoicesContainer.appendChild(optionDiv); drawPizza(canvas, fraction.num, fraction.den); optionDiv.addEventListener('click', handleChoiceClick); }); console.log("New round setup. Target:", currentOrder); } // --- Handle Pizza Choice Click --- function handleChoiceClick(event) { if (waitingForNext) return; // Don't process clicks during delay const clickedPizza = event.currentTarget; // The div element const clickedNum = parseInt(clickedPizza.dataset.num); const clickedDen = parseInt(clickedPizza.dataset.den); waitingForNext = true; // Prevent further clicks until next round // Remove event listeners from all options to prevent multiple clicks document.querySelectorAll('.pizza-option').forEach(opt => { // Clone and replace to remove listeners easily, or store listeners and remove them const clone = opt.cloneNode(true); opt.parentNode.replaceChild(clone, opt); }); // Check if correct if (clickedNum === currentOrder.num && clickedDen === currentOrder.den) { // Correct! score++; scoreDisplay.textContent = score; feedbackArea.textContent = `Yummy! That's ${currentOrder.num}/${currentOrder.den}! 🎉`; feedbackArea.className = 'correct-feedback'; clickedPizza.classList.add('correct-choice'); // Add animation class to the actual clicked element // Find the *new* clone in the DOM to add the class (since we replaced it) const newClickedElement = pizzaChoicesContainer.querySelector(`.pizza-option[data-num="${clickedNum}"][data-den="${clickedDen}"]`); if (newClickedElement) newClickedElement.classList.add('correct-choice'); } else { // Incorrect! feedbackArea.textContent = `Oops! That shows ${clickedNum}/${clickedDen}. Try the next one! 🤔`; feedbackArea.className = 'incorrect-feedback'; // Highlight the incorrect choice and the correct one (optional) const newClickedElement = pizzaChoicesContainer.querySelector(`.pizza-option[data-num="${clickedNum}"][data-den="${clickedDen}"]`); if (newClickedElement) newClickedElement.classList.add('incorrect-choice'); // Highlight the correct answer after a small delay setTimeout(() => { const correctElement = pizzaChoicesContainer.querySelector(`.pizza-option[data-num="${currentOrder.num}"][data-den="${currentOrder.den}"]`); if (correctElement) correctElement.classList.add('correct-choice'); // Use correct style to show answer }, 300); } // Load next round after a delay setTimeout(setupNewRound, 2000); // Wait 2 seconds before next round } // --- Initial Game Start --- setupNewRound(); }); // End DOMContentLoaded