<h1>Memory Game</h1>
    <div class="game-board" id="game-board">
    </div>
* {
  box-sizing: border-box;
}
h1{
    text-align: center;
}
:root {
  --x: 6;
  --y: 6;
}
.game-board {
  display: grid;
  grid-template-columns: repeat(var(--x), 1fr);
  grid-template-rows: repeat(var(--y), 1fr);
  gap: 10px;
  max-width: 500px;
  margin: auto;
  position: relative;
}
.card {
  width: 70px;
  height: 70px;
  position: relative;
  border-radius: 8px;
  transition: 0.6s;
  transform-style: preserve-3d;
  cursor: pointer;

}
.card-clicked {
  transform: rotateY(180deg);
}
.card-front {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
  background-image: url("https://iili.io/J5ANw2j.md.png");
  background-size: 70px 70px;
  -webkit-backface-visibility: hidden;
  -moz-backface-visibility: hidden;
  -o-backface-visibility: hidden;
  backface-visibility: hidden;
}
.card-back {
  transform: rotateY(180deg);
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 20px;
  -webkit-backface-visibility: hidden;
  -moz-backface-visibility: hidden;
  -o-backface-visibility: hidden;
  backface-visibility: hidden;
  border: 1px solid black;
  border-radius: 8px;
}
.empty-card {
  width: 70px;
  height: 70px;
}

/* CSS */
.button-6 {
  position:absolute;
  align-items: center;
  background-color: #FFFFFF;
  border: 1px solid rgba(0, 0, 0, 0.1);
  border-radius: .25rem;
  box-shadow: rgba(0, 0, 0, 0.02) 0 1px 3px 0;
  box-sizing: border-box;
  color: rgba(0, 0, 0, 0.85);
  cursor: pointer;
  display: inline-flex;
  font-family: system-ui,-apple-system,system-ui,"Helvetica Neue",Helvetica,Arial,sans-serif;
  font-size: 16px;
  font-weight: 600;
  justify-content: center;
  line-height: 1.25;
  margin: 0;
  min-height: 3rem;
  padding: calc(.875rem - 1px) calc(1.5rem - 1px);
  text-decoration: none;
  transition: all 250ms;
  user-select: none;
  -webkit-user-select: none;
  touch-action: manipulation;
  vertical-align: baseline;
  width: auto;
  top:50%;
  left:50%;
  transform: translate(-50%,-50%);

}

.button-6:hover,
.button-6:focus {
  border-color: rgba(0, 0, 0, 0.15);
  box-shadow: rgba(0, 0, 0, 0.1) 0 4px 12px;
  color: rgba(0, 0, 0, 0.65);
}

.button-6:hover {
  transform: translateY(-1px);
}

.button-6:active {
  background-color: #F0F0F1;
  border-color: rgba(0, 0, 0, 0.15);
  box-shadow: rgba(0, 0, 0, 0.06) 0 2px 4px;
  color: rgba(0, 0, 0, 0.65);
  transform: translateY(0);
}
const board = document.getElementById("game-board");

class Card {
  constructor(value) {
    this.value = value;
    this.element = null;
    this.isEmptyCard = false;
    this.init();
  }
  init() {
    this.generateFlipCard();
  }

  generateFlipCard() {
    const flipCard = document.createElement("div");
    const frontCard = document.createElement("div");
    const backCard = document.createElement("div");
    flipCard.className = "card";
    frontCard.className = "card-front";
    backCard.className = "card-back";
    flipCard.appendChild(frontCard);
    flipCard.appendChild(backCard);
    backCard.textContent = this.value;
    this.element = flipCard;
  }

  replaceWith() {
    const emptyCard = document.createElement("div");
    emptyCard.className = "empty-card";
    this.element.replaceWith(emptyCard);
    this.element = emptyCard;
    this.isEmptyCard = true;
  }

  toggleClass() {
    if (!this.isEmptyCard) {
      this.element.classList.toggle("card-clicked");
    }
  }

  getElement() {
    return this.element;
  }
}

class MemomryBoard {
  constructor(size, boardElement) {
    this.boardSize = size;
    this.boardElement = boardElement;
    this.init();
  }

  init() {
    this.cardNumber = [];
    this.nodeMap = new WeakMap();
    this.viewedCards = [];
    this.timer = null;
    this.disableClick = false;
    this.removedCards = 0;
    this.boardElement.innerHTML='';
    this.generateCardNumber();
    this.shuffleCards();
    this.addToDom();
  }
  generateCardNumber() {
    const cardNumber = (this.boardSize * this.boardSize) / 2;
    for (let i = 1; i <= cardNumber; i++) {
      const cardOne = new Card(i);
      const cardTwo = new Card(i);
      this.nodeMap.set(cardOne.getElement(), cardOne);
      this.nodeMap.set(cardTwo.getElement(), cardTwo);
      this.cardNumber.push(cardOne);
      this.cardNumber.push(cardTwo);
    }
  }

  addToDom() {
    const fragment = document.createDocumentFragment();
    for (let i = 0; i < this.cardNumber.length; i++) {
      fragment.appendChild(this.cardNumber[i].getElement());
    }

    this.boardElement.appendChild(fragment);
    this.bindEvents();
     }

  shuffleCards() {
    const length = this.cardNumber.length;
    for (let i = 0; i < length; i++) {
      const index = Math.floor(Math.random() * length);
      const temp = this.cardNumber[i];
      this.cardNumber[i] = this.cardNumber[index];
      this.cardNumber[index] = temp;
    }
  }

  startTimer(){
   this.timer = setTimeout(this.timerCallback.bind(this),3000);
  }

  timerCallback(){
   const length = this.viewedCards.length;
   if(length === 2){
    const [cardOne,cardTwo] = this.viewedCards;
    if(cardOne.value === cardTwo.value){
      cardOne.replaceWith();
      cardTwo.replaceWith();
      this.removedCards+=2;
    }else {
      cardOne.toggleClass();
      cardTwo.toggleClass();
    }
    this.viewedCards = [];
    this.disableClick = false;
    this.checkIfMatchCompleted();
   }else if(length === 1){
    const card = this.viewedCards.pop();
    card.toggleClass();
   } 
  }
  bindEvents(){
    this.boardElement.addEventListener("click", (event) => {
      if(!this.disableClick){
      const parentElement = event.target.parentElement;
      const haveClass = parentElement.classList.contains('card-clicked');
      if (this.nodeMap.has(parentElement)&&!haveClass) {
        const card = this.nodeMap.get(parentElement);
        this.viewedCards.push(card);
        if(this.viewedCards.length ===2){
          this.disableClick = true;
        }
        card.toggleClass();
        clearTimeout(this.timer);
        this.startTimer();
      }
    }
    });
  
  }
  checkIfMatchCompleted(){
    if(this.removedCards === this.boardSize*this.boardSize){
      this.boardElement.innerHTML = '';
      const button = document.createElement('button');
      button.className = 'button-6';
      button.textContent = 'Play Again';
      this.boardElement.appendChild(button);
      button.addEventListener('click',()=>{
        this.init();
      })
    }
  }
}

const Game = new MemomryBoard(6, board);
View Compiled
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.