Build a Flip the Card & Match Done Game using React

This application will provide users with the ability to play a fun and interactive game where they need to flip cards and match pairs with the same value. Along the way, we’ll implement features like keeping track of the player’s score, displaying a high score, and allowing the user to reset the game.

Prerequisites:

Approach:

  • Create a new React app using Create React App or any other method of your preference.
  • Create a clear project structure with directories for components, styles, and any other assets.
  • Design a Card component to represent each card in the game.
  • Include the state to manage whether the card is flipped or matched.
  • Implement logic to flip the card on click.
  • Decide on the number of cards and their values for the game.
  • Manage the game state to keep track of flipped cards, matched cards, and the current score.
  • Develop logic to match pairs of cards and update the score accordingly.
  • Use CSS Grid or Flexbox to display the cards in a grid layout.
  • Render the Card components within the grid.
  • Style the Card component to make it visually appealing.
  • Design separate styles for flipped and matched cards.
  • Include game controls such as a score counter, high score tracker, and a reset button.
  • Implement functionality to reset the game when needed.

Steps to Build a filp the card and match done game:

Step 1: Initialize a new React project using create-react-app and Install necessary dependencies (react, react-dom, etc.).

npx create-react-app react-flip-match-game
cd react-flip-match-game

Step 2: Define the directory structure, including public and src directories. Create App.js, Card.js, and index.js files.

Step 3: Create Card.js to handle individual card rendering and flipping logic. Add properties for card state (flipped, matched) and styles.

Step 4: In App.js, initialize the game state (cards array, score, high score) using React state hooks. Implement shuffle logic to randomize cards. Handle card flipping, matching logic, and updating scores. Add a method to reset the game.

Step 5: Create index.css for the overall layout and styling of cards. Ensure styles are applied to make the game visually appealing.

Project Structure:

Project Folder Structure

The updated dependencies in package.json file will look like:

"dependencies": {
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
}

Example: Below is an example of filp the card and match done game using Svelte and React.

CSS
/* index.css */

code {
  font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
    monospace;
}
body {
  font-family: Arial, sans-serif;
  margin: 0;
  padding: 0;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
  background-color: #282c34;
  color: white;
}

.scoreboard {
  display: flex;
  justify-content: space-between;
  width: 300px;
  margin-bottom: 10px;
}

.board {
  display: flex;
  flex-wrap: wrap;
  width: 300px;
  gap: 10px;
}

.card {
  width: 60px;
  height: 60px;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: #61dafb;
  cursor: pointer;
  border-radius: 5px;
}

.card-content {
  font-size: 24px;
  color: #282c34;
}
JavaScript
// App.js

import React, { useState, useEffect } from 'react';
import Card from './Card';

const initialCards = [
  { id: 1, matched: false, value: 'A' },
  { id: 2, matched: false, value: 'A' },
  { id: 3, matched: false, value: 'B' },
  { id: 4, matched: false, value: 'B' },
  { id: 5, matched: false, value: 'C' },
  { id: 6, matched: false, value: 'C' },
  { id: 7, matched: false, value: 'D' },
  { id: 8, matched: false, value: 'D' },
  { id: 9, matched: false, value: 'E' },
  { id: 10, matched: false, value: 'E' },
  { id: 11, matched: false, value: 'F' },
  { id: 12, matched: false, value: 'F' }
];

export default function App() {
  const [cards, setCards] = useState([]);
  const [firstCard, setFirstCard] = useState(null);
  const [secondCard, setSecondCard] = useState(null);
  const [lockBoard, setLockBoard] = useState(false);
  const [score, setScore] = useState(0);
  const [highScore, setHighScore] = useState(0);

  useEffect(() => {
    setCards(shuffleArray([...initialCards]));
  }, []);

  const shuffleArray = (array) => {
    return array.sort(() => Math.random() - 0.5);
  };
  const flipCard = (card) => {
    if (lockBoard || card.flipped) return;
    if (card === firstCard) return;
  
    if (!firstCard) {
      setFirstCard(card);
      setCards(cards.map(c => (c.id === card.id ? { ...c, flipped: true } : c)));
      return;
    }
  
    setSecondCard(card);
    setCards(cards.map(c => (c.id === card.id ? { ...c, flipped: true } : c)));
    setLockBoard(true);
  
    if (firstCard.value === card.value) {
      setCards(cards.map(c => (c.value === card.value ? { ...c, matched: true } : c)));
      setScore(score + 10);
      if (score + 10 > highScore) {
        setHighScore(score + 10);
      }
      resetBoard();
    } else {
      setTimeout(() => {
        setCards(cards.map(c => (c.id === card.id || c.id === firstCard.id ? { ...c, flipped: false } : c)));
        resetBoard();
      }, 1000);
    }
  };

  const resetBoard = () => {
    setFirstCard(null);
    setSecondCard(null);
    setLockBoard(false);
  };

  const resetGame = () => {
    setScore(0);
    setCards(shuffleArray([...initialCards]));
  };

  return (
    <>
      <div className="scoreboard">
        <div>Score: {score}</div>
        <div>High Score: {highScore}</div>
        <button onClick={resetGame} >Reset Game</button>
      </div>
      <div className="board">
        {cards.map(card => (
          <Card key={card.id} card={card} onClick={() => flipCard(card)} />
        ))}
      </div>
    </>
  );
}
JavaScript
// Card.js

import React from 'react';

export default function Card({ card, onClick }) {
  return (
    <div className="card" onClick={onClick}>
      <div className="card-content">
        {card.flipped || card.matched ? card.value : '?'}
      </div>
    </div>
  );
}
JavaScript
// index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './components/App';

ReactDOM.render(<App />, document.getElementById('root'));

Start your app using the following command:

npm start

Output:

Flip the card game