Project - 6
Project 6: Memory Match Game
Build a classic memory game where players flip cards and try to find matching pairs.
Your challenge: Shuffle the cards, reveal two at a time, count each move, keep matching pairs visible, and show a message when every pair is found.
Create the cards
The cards array contains two copies of every symbol. After shuffling, create one button for each item.
Store the symbol on the button with: card.dataset.symbol = symbol;
Flip two cards
When the first card is clicked, save it in first. When another card is clicked, save it in second and increase the move counter.
Check for a match
Compare first.dataset.symbol and second.dataset.symbol.
If they match, leave them visible. If they do not match, hide them again after a short delay with setTimeout().
Detect the win
Increase matched by two whenever a pair is found.
When matched === cards.length, every card has been matched and the game is complete.
Try it: Finish the game and see how few moves you can use.
Good JavaScript habit: Use a lock variable while unmatched cards are waiting to flip back. This prevents extra clicks from interfering with the current turn.
👀 Show Full Working Solution
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Memory Match</title>
<style>
body {
background: #000;
color: #8A8A8A;
font-family: 'Courier New', monospace;
text-align: center;
padding: 40px;
margin: 0;
}
.grid {
display: grid;
grid-template-columns: repeat(4, 80px);
gap: 10px;
justify-content: center;
margin: 20px auto;
}
.card {
width: 80px;
height: 80px;
background: #111;
color: #fff;
border: 1px solid #8A8A8A;
border-radius: 6px;
font-size: 2rem;
cursor: pointer;
}
.card:focus-visible {
outline: 3px solid #fff;
outline-offset: 3px;
}
#status {
min-height: 24px;
}
</style>
</head>
<body>
<h2>Memory Match Game</h2>
<p>Moves: <span id="moves">0</span></p>
<div id="game" class="grid"></div>
<p id="status" aria-live="polite"></p>
<script>
const symbols = [
"🍎", "🍌", "🍇", "🍒",
"🍉", "🍍", "🥝", "🍑"
];
let cards = [...symbols, ...symbols];
let first = null;
let second = null;
let lock = false;
let moves = 0;
let matched = 0;
cards.sort(function() {
return Math.random() - 0.5;
});
const game =
document.getElementById("game");
const movesDisplay =
document.getElementById("moves");
const status =
document.getElementById("status");
function createBoard() {
game.textContent = "";
cards.forEach(function(symbol) {
const card =
document.createElement("button");
card.className = "card";
card.type = "button";
card.dataset.symbol = symbol;
card.textContent = "";
card.addEventListener("click", function() {
flipCard(card);
});
game.appendChild(card);
});
}
function flipCard(card) {
if (
lock ||
card === first ||
card.textContent !== ""
) {
return;
}
card.textContent =
card.dataset.symbol;
if (first === null) {
first = card;
} else {
second = card;
lock = true;
moves++;
movesDisplay.textContent = moves;
checkMatch();
}
}
function checkMatch() {
if (
first.dataset.symbol ===
second.dataset.symbol
) {
matched += 2;
resetTurn();
if (matched === cards.length) {
status.textContent =
"You matched every pair in " +
moves +
" moves!";
}
} else {
setTimeout(function() {
first.textContent = "";
second.textContent = "";
resetTurn();
}, 800);
}
}
function resetTurn() {
first = null;
second = null;
lock = false;
}
createBoard();
</script>
</body>
</html>