Download script.js from ParulPandey/Fraction_Pizza_Party: direct link, hf CLI and curl.
- Browser
- Download file 9.34 kB
-
https://huggingface.co/spaces/ParulPandey/Fraction_Pizza_Party/resolve/main/script.js
- Command line
-
hf download hf://spaces/ParulPandey/Fraction_Pizza_Party/script.js
-
curl -L -o script.js https://huggingface.co/spaces/ParulPandey/Fraction_Pizza_Party/resolve/main/script.js
9.34 kB
| 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 |