From ed8ba53fa2fbc4cbcebf3679b95643e6043b6952 Mon Sep 17 00:00:00 2001 From: Patel Bhavika Date: Wed, 20 May 2026 03:02:34 +0530 Subject: [PATCH] fix: resolve canvas error in game modals --- web-app/js/hero-canvas.js | 11 ++- web-app/js/projects.js | 109 ---------------------------- web-app/js/projects/whack-a-mole.js | 78 +++++++++++++++++--- 3 files changed, 75 insertions(+), 123 deletions(-) diff --git a/web-app/js/hero-canvas.js b/web-app/js/hero-canvas.js index 050f377..c6f7134 100644 --- a/web-app/js/hero-canvas.js +++ b/web-app/js/hero-canvas.js @@ -3,9 +3,11 @@ Fixed: canvas now fills 100% of hero section ═══════════════════════════════════════════ */ const canvas = document.getElementById('boardCanvas'); -const ctx = canvas.getContext('2d'); -/* Force canvas to fill the hero section absolutely */ +if (canvas) { + const ctx = canvas.getContext('2d'); + + /* Force canvas to fill the hero section absolutely */ (function positionCanvas() { const hero = canvas.closest('.hero-section') || canvas.parentElement; if (hero && getComputedStyle(hero).position === 'static') { @@ -289,6 +291,7 @@ function loop() { tokens.forEach(t => { t.update(); t.draw(); }); drawDice(); requestAnimationFrame(loop); -} + } -loop(); \ No newline at end of file + loop(); +} \ No newline at end of file diff --git a/web-app/js/projects.js b/web-app/js/projects.js index 433ae69..2628385 100644 --- a/web-app/js/projects.js +++ b/web-app/js/projects.js @@ -3471,115 +3471,7 @@ function getTowerOfHanoiHTML() { `; } -function initTowerOfHanoi() { - const canvas = document.getElementById('hanoiCanvas'); - const ctx = canvas.getContext('2d'); - const diskCountInput = document.getElementById('diskCount'); - const solveBtn = document.getElementById('solveBtn'); - const resetBtn = document.getElementById('resetHanoi'); - const moveCountEl = document.getElementById('moveCount'); - const optimalMovesEl = document.getElementById('optimalMoves'); - - let towers = [[], [], []]; - let diskCount = 3; - let moveCount = 0; - let isAnimating = false; - let shouldStop = false; - - const towerX = [200, 400, 600]; - const baseY = 350; - const diskHeight = 20; - const maxDiskWidth = 120; - const colors = ['#ff6b6b', '#f59e0b', '#10b981', '#06b6d4', '#6366f1', '#8b5cf6', '#ec4899']; - - function initTowers() { - towers = [[], [], []]; - moveCount = 0; - diskCount = parseInt(diskCountInput.value) || 3; - //Reset animation state - isAnimating = false; - solveBtn.disabled = false; - - for (let i = diskCount; i >= 1; i--) { - towers[0].push(i); - } - - optimalMovesEl.textContent = Math.pow(2, diskCount) - 1; - moveCountEl.textContent = '0'; - drawTowers(); - } - - function drawTowers() { - ctx.clearRect(0, 0, canvas.width, canvas.height); - - // Draw bases and poles - ctx.fillStyle = '#64748b'; - for (let i = 0; i < 3; i++) { - // Pole - ctx.fillRect(towerX[i] - 5, baseY - 200, 10, 200); - // Base - ctx.fillRect(towerX[i] - 80, baseY, 160, 10); - } - - // Draw disks - for (let tower = 0; tower < 3; tower++) { - for (let disk = 0; disk < towers[tower].length; disk++) { - const diskSize = towers[tower][disk]; - const diskWidth = (maxDiskWidth * diskSize) / diskCount; - const x = towerX[tower] - diskWidth / 2; - const y = baseY - (disk + 1) * diskHeight; - - // Disk with gradient - const gradient = ctx.createLinearGradient(x, y, x + diskWidth, y + diskHeight); - gradient.addColorStop(0, colors[diskSize - 1]); - gradient.addColorStop(1, colors[diskSize - 1] + 'aa'); - - ctx.fillStyle = gradient; - ctx.fillRect(x, y, diskWidth, diskHeight - 2); - - // Border - ctx.strokeStyle = '#1e293b'; - ctx.lineWidth = 2; - ctx.strokeRect(x, y, diskWidth, diskHeight - 2); - - // Number - ctx.fillStyle = 'white'; - ctx.font = 'bold 12px Arial'; - ctx.textAlign = 'center'; - ctx.fillText(diskSize, towerX[tower], y + diskHeight / 2 + 4); - } - } - } - - async function moveDisk(from, to) { - if(shouldStop) return; - - const disk = towers[from].pop(); - towers[to].push(disk); - moveCount++; - moveCountEl.textContent = moveCount; - - drawTowers(); - await new Promise(resolve => setTimeout(resolve, 500)); - } - - async function solveHanoi(n, from, to, aux) { - if (n === 1) { - await moveDisk(from, to); - return; - } - - await solveHanoi(n - 1, from, aux, to); - await moveDisk(from, to); - await solveHanoi(n - 1, aux, to, from); - } - - async function solve() { - if (isAnimating) return; - - return projects[projectName] || '

Project Coming Soon!

'; -} function getTicTacToeHTML() { return ` @@ -3840,7 +3732,6 @@ function initializeProject(projectName) { initializers[projectName](); } } -} //Removed Redundant game and project Logics and seperated them to different individual files located at (web-app/js/projects/) diff --git a/web-app/js/projects/whack-a-mole.js b/web-app/js/projects/whack-a-mole.js index 7eeecc1..c3a3bc3 100644 --- a/web-app/js/projects/whack-a-mole.js +++ b/web-app/js/projects/whack-a-mole.js @@ -45,6 +45,8 @@ function initWhackaMole() { let timeLeft = 30; let gameActive = false; let activeIndex = -1; + let lastActiveIndex = -1; + let lastActiveTime = 0; let timerId = null; let moleId = null; @@ -52,32 +54,80 @@ function initWhackaMole() { const button = document.createElement('button'); button.type = 'button'; button.className = 'whack-hole'; + button.textContent = '🕳️'; button.setAttribute('aria-label', `Hole ${index + 1}`); - button.addEventListener('click', () => { - if (!gameActive || index !== activeIndex) return; + + const handleHit = (e) => { + if (e) e.preventDefault(); + if (!gameActive) return; + + const isDirectHit = (index === activeIndex); + const isGraceHit = (index === lastActiveIndex && (Date.now() - lastActiveTime) < 150); + + if (!isDirectHit && !isGraceHit) return; + score += 1; scoreEl.textContent = String(score); - messageEl.textContent = 'Hit!'; + messageEl.textContent = 'Hit! 🔨'; + button.textContent = '💥'; + button.classList.remove('active'); + + // Set to -1 immediately to prevent double hits + activeIndex = -1; + lastActiveIndex = -1; + clearTimeout(moleId); - showMole(); - }); + moleId = setTimeout(showMole, 250); + }; + + button.addEventListener('pointerdown', handleHit); + button.addEventListener('click', handleHit); + board.appendChild(button); return button; }); function showMole() { - holes.forEach(hole => hole.classList.remove('active')); - activeIndex = Math.floor(Math.random() * holes.length); + if (!gameActive) return; + + // Save previous active mole state for grace period + if (activeIndex !== -1) { + lastActiveIndex = activeIndex; + lastActiveTime = Date.now(); + } + + holes.forEach(hole => { + hole.classList.remove('active'); + hole.textContent = '🕳️'; + }); + + // Choose a new hole, ensuring it is different from the current one + let newIndex; + do { + newIndex = Math.floor(Math.random() * holes.length); + } while (newIndex === activeIndex && holes.length > 1); + + activeIndex = newIndex; holes[activeIndex].classList.add('active'); + holes[activeIndex].textContent = '🐭'; + moleId = setTimeout(showMole, 850); } function stopGame(finalMessage) { gameActive = false; clearInterval(timerId); + timerId = null; clearTimeout(moleId); - holes.forEach(hole => hole.classList.remove('active')); + moleId = null; + activeIndex = -1; + lastActiveIndex = -1; + holes.forEach(hole => { + hole.classList.remove('active'); + hole.textContent = '🕳️'; + }); messageEl.textContent = finalMessage; + startBtn.disabled = false; } function startGame() { @@ -87,9 +137,9 @@ function initWhackaMole() { scoreEl.textContent = '0'; timeEl.textContent = '30'; messageEl.textContent = 'Go!'; + startBtn.disabled = true; clearInterval(timerId); clearTimeout(moleId); - showMole(); timerId = setInterval(() => { timeLeft -= 1; timeEl.textContent = String(timeLeft); @@ -97,19 +147,27 @@ function initWhackaMole() { stopGame(`Time! Final score: ${score}`); } }, 1000); + showMole(); } startBtn.addEventListener('click', startGame); resetBtn.addEventListener('click', () => { clearInterval(timerId); + timerId = null; clearTimeout(moleId); + moleId = null; score = 0; timeLeft = 30; gameActive = false; activeIndex = -1; - holes.forEach(hole => hole.classList.remove('active')); + lastActiveIndex = -1; + holes.forEach(hole => { + hole.classList.remove('active'); + hole.textContent = '🕳️'; + }); scoreEl.textContent = '0'; timeEl.textContent = '30'; messageEl.textContent = 'Hit the mole when it appears.'; + startBtn.disabled = false; }); } \ No newline at end of file