Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added assets/whack-a-mole.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
42 changes: 42 additions & 0 deletions en/beginner-projects/whack-a-mole.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# 🦫 Whack-a-Mole Game

![Whack-a-Mole Preview](../../assets/whack-a-mole.png)

## Description

A fun and fast-paced reflex game where players “whack” moles as they randomly pop out of holes. Each successful hit earns you points — but be quick, because the mole disappears in a second! The game runs for a limited time, making it both exciting and challenging.

## Features

- Start button to begin the game
- Random mole appearances in 9 different holes
- Real-time score tracking
- Automatic 30-second game duration
- Alert message showing final score when time’s up

## Concepts Practiced

- DOM manipulation and dynamic element creation
- Event listeners for interactive clicks
- Randomization and timing using `Math.random()` and `setTimeout()`
- Basic game loop logic
- CSS animations for mole movement

## Bonus Challenge

- Add **levels** (Easy, Medium, Hard) that increase mole speed
- Add a **visible countdown timer**
Copy link

Copilot AI Oct 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This bonus challenge suggests adding a visible countdown timer, but the implementation already includes a countdown timer displayed in the UI (<span id=\"time-left\">). This should be updated to reflect that a timer is already implemented and suggest alternative enhancements.

Suggested change
- Add a **visible countdown timer**
- Add a **pause/resume button** to control the game

Copilot uses AI. Check for mistakes.
- Store and display **high scores** using `localStorage`
- Add **sound effects** when the mole is clicked
- Use **images or emojis** to customize the mole design

Comment on lines +27 to +32
Copy link

Copilot AI Oct 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This bonus challenge suggests adding difficulty levels, but the implementation already includes four difficulty levels (Beginner, Easy, Medium, Hard). This should be updated to reflect that difficulty levels are already implemented and suggest alternative enhancements.

Suggested change
- Add **levels** (Easy, Medium, Hard) that increase mole speed
- Add a **visible countdown timer**
- Store and display **high scores** using `localStorage`
- Add **sound effects** when the mole is clicked
- Use **images or emojis** to customize the mole design
- Add **power-ups** (e.g., double points, freeze mole, extra time)
- Add a **visible countdown timer**
- Store and display **high scores** using `localStorage`
- Add **sound effects** when the mole is clicked
- Use **images or emojis** to customize the mole design
- Add a **leaderboard** to show top scores
- Implement a **multiplayer mode** (local or online)
- Add **custom themes** or color schemes
- Improve **accessibility** (keyboard controls, screen reader support)

Copilot uses AI. Check for mistakes.
## Live Demo

<div align="center">
<iframe src="https://codesandbox.io/p/sandbox/hwr4cq"
style="width:100%; height: 500px; border:0; border-radius: 4px; overflow:hidden;"
title="whack-a-mole-game"
allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking"
sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
></iframe>
</div>
37 changes: 37 additions & 0 deletions examples/Whack-A-Mole/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Whack-a-Mole — Reflex Game 🦫

This is a fun and interactive **Whack-a-Mole** reflex game built using **HTML, CSS, and modern JavaScript (ES Modules)**.
Players must click (or “whack”) the mole as it randomly pops out of one of the holes before it disappears — testing their speed and reaction time!

## Features

- 🎯 **Fast-paced gameplay** — moles appear randomly across the board.
- ⏱️ **30-second timer** — challenge yourself to score as high as possible within the time limit.
Copy link

Copilot AI Oct 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation states a fixed 30-second timer, but the implementation supports configurable durations per difficulty level (all currently set to 30 seconds in LEVELS object). Consider updating this to reflect that the duration is configurable or difficulty-dependent.

Copilot uses AI. Check for mistakes.
- 🧠 **Live score tracking** — updates instantly with each successful hit.
- 💥 **Smooth animations** — CSS-based mole pop-up effect for a polished experience.
- ⚡ Built using **pure HTML, CSS, and JavaScript (no libraries or frameworks)**.

## Files

- `index.html` — main structure and layout of the game board.
- `styles.css` — visual design, layout grid, and animations.
- `index.mjs` — game logic for mole appearance, scoring, and timer handling.

## How to Play

1. Open `index.html` in your browser (Chrome, Edge, or Firefox recommended).
2. Click the **“Start Game”** button to begin.
3. Moles will pop up randomly in different holes — **click them as fast as you can!**
4. Each successful hit gives you **+1 point**.
5. After 30 seconds, the game ends and your **final score** is displayed.
6. Click **“Start Game”** again to play another round.

## Notes

- Uses **JavaScript’s `setTimeout()`** for mole timing and random placement.
- A great beginner project to understand **event handling, DOM updates, and randomization**.
- Fully responsive — works on both **desktop and mobile** devices.

---

✨ **Test your reflexes and see how many moles you can whack!**
41 changes: 41 additions & 0 deletions examples/Whack-A-Mole/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Whack-a-Mole Game 🦫</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<h1>Whack-a-Mole 🦫</h1>

<div class="scoreboard">
<p>Score: <span id="score">0</span></p>
<label for="difficulty">Difficulty:</label>
<select id="difficulty">
<option value="beginner" selected>Beginner</option>
<option value="easy">Easy</option>
<option value="medium">Medium</option>
<option value="hard">Hard</option>
</select>
<p>Time: <span id="time-left">30</span>s</p>
<button id="start-btn">Start Game</button>
<button id="reset-btn" disabled>Reset Game</button>
</div>

<div class="grid">
<!-- 9 holes -->
<div class="hole" data-index="0"></div>
<div class="hole" data-index="1"></div>
<div class="hole" data-index="2"></div>
<div class="hole" data-index="3"></div>
<div class="hole" data-index="4"></div>
<div class="hole" data-index="5"></div>
<div class="hole" data-index="6"></div>
<div class="hole" data-index="7"></div>
<div class="hole" data-index="8"></div>
</div>

<script type="module" src="index.mjs"></script>
</body>
</html>
163 changes: 163 additions & 0 deletions examples/Whack-A-Mole/index.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
const holes = document.querySelectorAll(".hole");
const scoreDisplay = document.getElementById("score");
const timeLeftDisplay = document.getElementById("time-left");
const difficultySelect = document.getElementById("difficulty");
const startBtn = document.getElementById("start-btn");
const resetBtn = document.getElementById("reset-btn");

let score = 0;
let gameActive = false;
let moleTimer; // controls despawn/next-spawn timing
let endTimer; // controls game end
let tickTimer; // countdown display timer
let currentMole = null;

const LEVELS = {
beginner: {
moleVisibleMs: 3000,
respawnDelayMs: 1200,
totalTimeSec: 30,
animationSec: 1.8,
},
easy: {
moleVisibleMs: 2200,
respawnDelayMs: 900,
totalTimeSec: 30,
animationSec: 1.3,
},
medium: {
moleVisibleMs: 1500,
respawnDelayMs: 500,
totalTimeSec: 30,
animationSec: 1.0,
},
hard: {
moleVisibleMs: 1000,
respawnDelayMs: 300,
totalTimeSec: 30,
animationSec: 0.7,
},
};

// Spawn a mole in a random hole
function showMole() {
if (!gameActive) return;

// Cleanup any existing mole
if (currentMole && currentMole.isConnected) {
currentMole.remove();
}

const randomIndex = Math.floor(Math.random() * holes.length);
const hole = holes[randomIndex];

const mole = document.createElement("div");
mole.classList.add("mole");
hole.appendChild(mole);
currentMole = mole;

// Tune the animation speed to the selected difficulty
const { moleVisibleMs, respawnDelayMs, animationSec } = LEVELS[difficultySelect.value] || LEVELS.easy;
mole.style.animationDuration = `${animationSec}s`;

// Despawn after a short time and spawn the next one with a brief delay
clearTimeout(moleTimer);
moleTimer = setTimeout(() => {
if (mole.isConnected) mole.remove();
if (gameActive) {
setTimeout(() => showMole(), respawnDelayMs);
}
}, moleVisibleMs);
}

// Handle hits (click or touch/pointer)
holes.forEach((hole) => {
// Use pointerdown for better responsiveness across mouse/touch
hole.addEventListener("pointerdown", (e) => {
const target = e.target;
if (target && target.classList && target.classList.contains("mole")) {
// Register hit
score++;
scoreDisplay.textContent = score;

// Remove current mole and spawn the next immediately
clearTimeout(moleTimer);
target.remove();
if (gameActive) {
const { respawnDelayMs } = LEVELS[difficultySelect.value] || LEVELS.easy;
// Add a smooth delay after whack before next mole
setTimeout(() => showMole(), respawnDelayMs);
}
}
});
});

// Start game logic
startBtn.addEventListener("click", () => {
if (gameActive) return;

// Reset state
score = 0;
scoreDisplay.textContent = score;
gameActive = true;
startBtn.textContent = "Playing...";
startBtn.disabled = true;
resetBtn.disabled = false;
difficultySelect.disabled = true; // Lock difficulty during game

const { totalTimeSec } = LEVELS[difficultySelect.value] || LEVELS.beginner;
timeLeftDisplay.textContent = totalTimeSec;

// Kick off the loop
showMole();

// Stop after specified duration
clearTimeout(endTimer);
clearInterval(tickTimer);

const start = Date.now();
const totalMs = totalTimeSec * 1000;

// Countdown display (per second)
tickTimer = setInterval(() => {
const elapsed = Date.now() - start;
const remaining = Math.max(0, Math.ceil((totalMs - elapsed) / 1000));
timeLeftDisplay.textContent = remaining;
}, 200);

endTimer = setTimeout(() => {
gameActive = false;
clearTimeout(moleTimer);
clearInterval(tickTimer);
timeLeftDisplay.textContent = 0;
if (currentMole && currentMole.isConnected) currentMole.remove();
startBtn.textContent = "Start Game";
startBtn.disabled = false;
difficultySelect.disabled = false; // Re-enable difficulty selection
alert(`⏱️ Time's up! Your score: ${score}`);
}, totalMs);
});

// Reset game logic
resetBtn.addEventListener("click", () => {
if (!gameActive) return;

// Stop the game
gameActive = false;
clearTimeout(moleTimer);
clearTimeout(endTimer);
clearInterval(tickTimer);

// Clean up mole
if (currentMole && currentMole.isConnected) currentMole.remove();

// Reset UI
score = 0;
scoreDisplay.textContent = score;
const { totalTimeSec } = LEVELS[difficultySelect.value] || LEVELS.beginner;
timeLeftDisplay.textContent = totalTimeSec;
startBtn.textContent = "Start Game";
startBtn.disabled = false;
resetBtn.disabled = true;
difficultySelect.disabled = false; // Allow difficulty change after reset
});
Loading