Mystery Game #7
← Back to Games List
// Whack-a-Mole Game Implementation
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
// Game settings
const gridSize = 3;
const holeSize = 80;
const padding = 40;
const totalWidth = (holeSize + padding) * gridSize;
const totalHeight = (holeSize + padding) * gridSize;
// Center the grid
canvas.width = totalWidth + padding;
canvas.height = totalHeight + padding + 50; // Extra space for score
// Game state
const holes = [];
let score = 0;
let timeLeft = 30;
let gameActive = false;
let lastSpawnTime = 0;
let spawnInterval = 1000;
let minSpawnInterval = 500;
// Create holes grid
function createHoles() {
for (let row = 0; row < gridSize; row++) {
for (let col = 0; col < gridSize; col++) {
const x = col * (holeSize + padding) + padding;
const y = row * (holeSize + padding) + padding;
holes.push({
x: x,
y: y,
size: holeSize,
active: false,
timeUp: 0,
upDuration: 0
});
}
}
}
// Handle mouse click
canvas.addEventListener('click', function(e) {
if (!gameActive) {
startGame();
return;
}
const rect = canvas.getBoundingClientRect();
const clickX = e.clientX - rect.left;
const clickY = e.clientY - rect.top;
holes.forEach(hole => {
if (hole.active &&
clickX > hole.x && clickX < hole.x + hole.size &&
clickY > hole.y && clickY < hole.y + hole.size) {
score += 10;
hole.active = false;
spawnInterval = Math.max(minSpawnInterval, spawnInterval - 10);
}
});
});
function spawnTarget() {
if (!gameActive) return;
const now = Date.now();
if (now - lastSpawnTime < spawnInterval) return;
// Deactivate any expired targets
holes.forEach(hole => {
if (hole.active && now > hole.timeUp) {
hole.active = false;
}
});
// Find inactive holes
const inactiveHoles = holes.filter(hole => !hole.active);
if (inactiveHoles.length === 0) return;
// Randomly activate one
const target = inactiveHoles[Math.floor(Math.random() * inactiveHoles.length)];
target.active = true;
target.upDuration = Math.random() * 500 + 750; // Random duration between 750-1250ms
target.timeUp = now + target.upDuration;
lastSpawnTime = now;
}
function draw() {
// Clear canvas
ctx.fillStyle = 'skyblue';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw holes and targets
holes.forEach(hole => {
// Draw hole (dark circle)
ctx.beginPath();
ctx.arc(hole.x + hole.size/2, hole.y + hole.size/2, hole.size/2, 0, Math.PI * 2);
ctx.fillStyle = '#333';
ctx.fill();
// Draw target if active
if (hole.active) {
ctx.beginPath();
ctx.arc(hole.x + hole.size/2, hole.y + hole.size/2 - 10, hole.size/3, 0, Math.PI * 2);
ctx.fillStyle = 'brown';
ctx.fill();
// Draw eyes
ctx.fillStyle = 'black';
ctx.beginPath();
ctx.arc(hole.x + hole.size/2 - 8, hole.y + hole.size/2 - 15, 3, 0, Math.PI * 2);
ctx.arc(hole.x + hole.size/2 + 8, hole.y + hole.size/2 - 15, 3, 0, Math.PI * 2);
ctx.fill();
}
});
// Draw score and time
ctx.fillStyle = 'black';
ctx.font = '20px Arial';
ctx.textAlign = 'left';
ctx.fillText('Score: ' + score, 10, canvas.height - 20);
ctx.textAlign = 'right';
ctx.fillText('Time: ' + timeLeft, canvas.width - 10, canvas.height - 20);
// Draw start message if game not active
if (!gameActive) {
ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = 'white';
ctx.font = '30px Arial';
ctx.textAlign = 'center';
if (timeLeft === 30) {
ctx.fillText('Click to Start!', canvas.width/2, canvas.height/2);
} else {
ctx.fillText('Game Over!', canvas.width/2, canvas.height/2 - 30);
ctx.font = '20px Arial';
ctx.fillText('Final Score: ' + score, canvas.width/2, canvas.height/2 + 10);
ctx.fillText('Click to Play Again', canvas.width/2, canvas.height/2 + 40);
}
}
}
function startGame() {
score = 0;
timeLeft = 30;
gameActive = true;
spawnInterval = 1000;
lastSpawnTime = Date.now();
// Reset all holes
holes.forEach(hole => {
hole.active = false;
});
// Start countdown
const timer = setInterval(() => {
if (!gameActive) {
clearInterval(timer);
return;
}
timeLeft--;
if (timeLeft <= 0) {
gameActive = false;
clearInterval(timer);
}
}, 1000);
}
function gameLoop() {
spawnTarget();
draw();
requestAnimationFrame(gameLoop);
}
// Initialize game
createHoles();
gameLoop();
# Whack-a-Mole Game Implementation
import pygame
import random
import time
from dataclasses import dataclass
from typing import List
@dataclass
class Hole:
x: int
y: int
size: int
active: bool = False
time_up: float = 0
up_duration: float = 0
class WhackAMoleGame:
def __init__(self):
pygame.init()
# Game settings
self.grid_size = 3
self.hole_size = 80
self.padding = 40
self.total_width = (self.hole_size + self.padding) * self.grid_size + self.padding
self.total_height = (self.hole_size + self.padding) * self.grid_size + self.padding + 50
# Initialize display
self.screen = pygame.display.set_mode((self.total_width, self.total_height))
pygame.display.set_caption('Whack-a-Mole')
self.clock = pygame.time.Clock()
# Game state
self.holes: List[Hole] = []
self.score = 0
self.time_left = 30
self.game_active = False
self.last_spawn_time = 0
self.spawn_interval = 1000
self.min_spawn_interval = 500
self.create_holes()
def create_holes(self):
for row in range(self.grid_size):
for col in range(self.grid_size):
x = col * (self.hole_size + self.padding) + self.padding
y = row * (self.hole_size + self.padding) + self.padding
self.holes.append(Hole(x=x, y=y, size=self.hole_size))
def handle_input(self) -> bool:
for event in pygame.event.get():
if event.type == pygame.QUIT:
return False
if event.type == pygame.MOUSEBUTTONDOWN:
if not self.game_active:
self.start_game()
else:
mouse_x, mouse_y = pygame.mouse.get_pos()
self.check_mole_hit(mouse_x, mouse_y)
return True
def check_mole_hit(self, x: int, y: int):
for hole in self.holes:
if (hole.active and
x > hole.x and x < hole.x + hole.size and
y > hole.y and y < hole.y + hole.size):
self.score += 10
hole.active = False
self.spawn_interval = max(self.min_spawn_interval,
self.spawn_interval - 10)
def spawn_target(self):
if not self.game_active:
return
now = time.time() * 1000 # Convert to milliseconds
if now - self.last_spawn_time < self.spawn_interval:
return
# Deactivate expired targets
for hole in self.holes:
if hole.active and now > hole.time_up:
hole.active = False
# Find inactive holes
inactive_holes = [hole for hole in self.holes if not hole.active]
if not inactive_holes:
return
# Randomly activate one
target = random.choice(inactive_holes)
target.active = True
target.up_duration = random.random() * 500 + 750
target.time_up = now + target.up_duration
self.last_spawn_time = now
def draw(self):
# Clear screen
self.screen.fill((135, 206, 235)) # skyblue
# Draw holes and moles
for hole in self.holes:
# Draw hole
pygame.draw.circle(self.screen, (51, 51, 51), # dark gray
(hole.x + hole.size//2, hole.y + hole.size//2),
hole.size//2)
# Draw mole if active
if hole.active:
# Draw mole body
pygame.draw.circle(self.screen, (139, 69, 19), # brown
(hole.x + hole.size//2,
hole.y + hole.size//2 - 10),
hole.size//3)
# Draw eyes
pygame.draw.circle(self.screen, (0, 0, 0),
(hole.x + hole.size//2 - 8,
hole.y + hole.size//2 - 15), 3)
pygame.draw.circle(self.screen, (0, 0, 0),
(hole.x + hole.size//2 + 8,
hole.y + hole.size//2 - 15), 3)
# Draw score and time
font = pygame.font.Font(None, 36)
score_text = font.render(f'Score: {self.score}', True, (0, 0, 0))
time_text = font.render(f'Time: {self.time_left}', True, (0, 0, 0))
self.screen.blit(score_text, (10, self.total_height - 30))
self.screen.blit(time_text,
(self.total_width - 120, self.total_height - 30))
# Draw overlay if game not active
if not self.game_active:
overlay = pygame.Surface((self.total_width, self.total_height))
overlay.fill((0, 0, 0))
overlay.set_alpha(178) # 70% opacity
self.screen.blit(overlay, (0, 0))
font = pygame.font.Font(None, 48)
if self.time_left == 30:
text = font.render('Click to Start!', True, (255, 255, 255))
text_rect = text.get_rect(center=(self.total_width//2,
self.total_height//2))
self.screen.blit(text, text_rect)
else:
game_over = font.render('Game Over!', True, (255, 255, 255))
game_over_rect = game_over.get_rect(
center=(self.total_width//2, self.total_height//2 - 30))
self.screen.blit(game_over, game_over_rect)
font = pygame.font.Font(None, 36)
score = font.render(f'Final Score: {self.score}',
True, (255, 255, 255))
score_rect = score.get_rect(
center=(self.total_width//2, self.total_height//2 + 10))
self.screen.blit(score, score_rect)
play_again = font.render('Click to Play Again',
True, (255, 255, 255))
play_again_rect = play_again.get_rect(
center=(self.total_width//2, self.total_height//2 + 40))
self.screen.blit(play_again, play_again_rect)
pygame.display.flip()
def start_game(self):
self.score = 0
self.time_left = 30
self.game_active = True
self.spawn_interval = 1000
self.last_spawn_time = time.time() * 1000
# Reset holes
for hole in self.holes:
hole.active = False
def update_timer(self):
if self.game_active:
current_time = pygame.time.get_ticks()
if current_time - self.last_timer_update >= 1000:
self.time_left -= 1
self.last_timer_update = current_time
if self.time_left <= 0:
self.game_active = False
def run(self):
self.last_timer_update = pygame.time.get_ticks()
running = True
while running:
running = self.handle_input()
self.spawn_target()
self.update_timer()
self.draw()
self.clock.tick(60)
pygame.quit()
if __name__ == '__main__':
game = WhackAMoleGame()
game.run()
Play Game