The Code for Memory

              
                /*
                * Set symbols in an array
                */
                const symbols = [
                  "fas fa-chess",
                  "fas fa-chess",
                  "fa fa-chess-bishop",
                  "fa fa-chess-bishop",
                  "fa fa-chess-king",
                  "fa fa-chess-king",
                  "fa fa-chess-knight",
                  "fa fa-chess-knight",
                  "fa fa-chess-pawn",
                  "fa fa-chess-pawn",
                  "fa fa-chess-queen",
                  "fa fa-chess-queen",
                  "fa fa-chess-rook",
                  "fa fa-chess-rook",
                  "fa fa-chess-board",
                  "fa fa-chess-board",
                ];

                const deck = document.querySelector(".deck");
                const timer = document.querySelector(".timer");

                let openCards = [];
                let matchedCards = [];
                let timerOff = true;
                let time = 25;
                let gameTimer;

                /*
                * Start Game
                */
                function startGame() {
                  const resetBtn = document.querySelector(".restart");
                  resetBtn.addEventListener("click", restartGame);
                  displayTime();
                  displayDeck();
                }

                /*
                * Display game board
                */
                function displayDeck() {
                  shuffle(symbols);
                  // Create html for cards
                  for (let i = 0; i <= symbols.length; i++) {
                    const card = document.createElement("li");
                    card.classList.add("card");
                    card.innerHTML = ``;
                    deck.appendChild(card);

                    // Add click event to each card
                    clickCard(card);
                    deck.classList.remove("disable");
                  }
                }

                /*
                * Shuffle Cards
                */
                // Shuffle function from http://stackoverflow.com/a/2450976
                function shuffle(array) {
                  var currentIndex = array.length,
                    temporaryValue,
                    randomIndex;

                  while (currentIndex !== 0) {
                    randomIndex = Math.floor(Math.random() * currentIndex);
                    currentIndex -= 1;
                    temporaryValue = array[currentIndex];
                    array[currentIndex] = array[randomIndex];
                    array[randomIndex] = temporaryValue;
                  }

                  return array;
                }

                /*
                * Click Card Event
                */
                function clickCard(card) {
                  card.addEventListener("click", function () {
                    if (timerOff) {
                      startTimer();
                      timerOff = false;
                    }

                    const currentCard = this;
                    const previousCard = openCards[0];

                    disableClickOrNot(openCards);

                    // existing open card
                    if (openCards.length === 1) {
                      showCard(card);
                      addOpenCards(this);
                      checkMatch(currentCard, previousCard);
                    } else {
                      // no open card
                      showCard(card);
                      addOpenCards(this);
                    }
                  });
                }

                /*
                * Prevent more than two cards being flipped at a time.
                */
                function disableClickOrNot(array) {
                  if (array.length === 2) {
                    deck.classList.add("disable");
                  } else {
                    deck.classList.remove("disable");
                  }
                }

                /*
                * Show symbol of card
                */
                function showCard(card) {
                  card.classList.add("open", "show", "disable");
                }

                /*
                * Add open cards to 'openCards'
                */
                function addOpenCards(card) {
                  openCards.push(card);
                }

                /*
                * Check match
                */
                function checkMatch(currentCard, previousCard) {
                  disableClickOrNot(openCards);
                  if (currentCard.innerHTML === previousCard.innerHTML) {
                    cardsMatch(currentCard, previousCard);
                    openCards = [];
                    disableClickOrNot(openCards);
                  } else {
                    // wait 500ms
                    setTimeout(function () {
                      noMatch(currentCard, previousCard);
                    }, 500);
                    openCards = [];
                  }

                  moveCounter();
                  starDisplay();
                  gameOver();
                }

                /*
                * Cards match
                */
                function cardsMatch(currentCard, previousCard) {
                  currentCard.classList.add("match");
                  previousCard.classList.add("match");
                  addMatchedCards(currentCard, previousCard);
                }

                /*
                * Add matching cards to 'matchedCards'
                */
                function addMatchedCards(currentCard, previousCard) {
                  matchedCards.push(currentCard);
                  matchedCards.push(previousCard);
                }

                /*
                * Cards don't match
                */
                function noMatch(currentCard, previousCard) {
                  currentCard.classList.remove("open", "show", "disable");
                  previousCard.classList.remove("open", "show", "disable");
                  disableClickOrNot(openCards);
                }

                /*
                * Move counter
                */
                let displayMoves = document.querySelector(".moves");
                let moves = 0;
                displayMoves.innerHTML = moves + " moves";
                function moveCounter() {
                  moves++;

                  if (moves === 1) {
                    displayMoves.innerHTML = moves + " move";
                  } else {
                    displayMoves.innerHTML = moves + " moves";
                  }
                  return displayMoves;
                }

                /*
                * Star display
                */
                let displayStars = document.querySelector(".stars");
                let stars = `<li><i class="fa fa-star"></i></li>
                             <li><i class="fa fa-star"></i></li>
                             <li><i class="fa fa-star"></i></li>`;
                function starDisplay() {
                  switch (moves) {
                    case 17:
                      displayStars.innerHTML = `<li><i class="fa fa-star"></i></li>
                                                <li><i class="fa fa-star"></i></li>`;
                      break;
                    case 24:
                      displayStars.innerHTML = `<li><i class="fa fa-star"></i></li>`;
                  }
                }

                /*
                * Reset game
                */
                function restartGame() {
                  // remove cards
                  deck.innerHTML = "";

                  // call 'startGame' to create new board
                  startGame();

                  // empty 'openCards'
                  openCards = [];

                  // reset timer
                  stopTimer();
                  timerOff = true;
                  time = 25;
                  displayTime();

                  // reset all stats
                  matchedCards = [];
                  moves = 0;
                  displayMoves.innerHTML = moves + " moves";
                  displayStars.innerHTML = stars;
                }

                /*
                * Replay game
                */
                function replayGame() {
                  restartGame();
                }

                /*
                * End the game
                */
                function gameOver() {
                  if (matchedCards.length === symbols.length) {
                    stopTimer(gameTimer);
                    alert("Congratulations! You matched all the cards and won.");
                  }
                }

                /*
                * Start game timer
                */
                function startTimer() {
                  gameTimer = setInterval(function () {
                    time--;
                    displayTime();
                  }, 1000);
                }

                /*
                * Display game timer
                */
                function displayTime() {
                  minutes = Math.floor(time / 60);
                  seconds = time % 60;
                  if (seconds >= 0) {
                    if (seconds <= 10) {
                      timer.innerHTML = `${minutes}:0${seconds}`;
                    } else {
                      timer.innerHTML = `${minutes}:${seconds}`;
                    }
                  } else {
                    stopTimer();
                    deck.classList.add("disable");
                    alert("Time ran out and you lost!");
                  }
                }

                /*
                * Stop game timer
                */
                function stopTimer() {
                  clearInterval(gameTimer);
                }

                ////////// Start game for the first time
                startGame();

              
            

The code is structured into 19 functions. This code is still a work in progress and I will update the descriptions/reasoning for my functions as I continue working on this project.

startGame()

This function resets the stats and displays the board and cards.

displayDeck()

This function calls the shuffle function, displays the cards and calls the clickCard function.

shuffle()

This function takes in an array and randomly changes the index for each item in the array. This new order is then returned.

clickCard()

This function listens for a click on any of the cards. Clicking a card for the first time will start the timer for the game.

disableClickOrNot()

This function prevents more than two cards being shown at the same time. This is called in the clickCard function as well as the checkMatch and the noMatch functions.

showCard()

This function is used to show a card and is called in the clickCard function.

addOpenCards()

This function pushes a card to the openCards array and it is called in the clickCard function.

checkMatch()

This function gets called in the clickCard function to compare if the two items in the openCards array match based on their innerHTML values. This will also clear the openCards array. After the checks are done I am also updating the stats and checking if the game is over.

cardsMatch()

This uses the currentCard and previousCard set in the clickCard function and passed through checkMatch function to add the match class for styling. Then it passes the currentCard and previousCard to the addMatchedCards function.

addMatchedCards()

This function is used to push the matched cards to the matchedCards array which helps determine if the game is over.

noMatch()

This function is used to flip the cards back over if no match was determined.

moveCounter()

Each time the checkMatch function runs this increments the moves by 1.

displayStars()

Based on the number of moves this function displays 3, 2, or 1 star. This function is called in the checkMatch function.

restartGame()

This function resets the stats, timer, and cards without doing a full page refresh.

replayGame()

Calls the restart game function and may eventually hide a modal as well.

gameOver()

This function is checking the matchedCards array length to the length of the symbols array to determine if the game is over. If the game is over the timer is stopped and an alert is sent to the browser.

startTimer()

This calls the displayTime function and decreases the time by 1.

displayTime()

This function calculates the time and displays the new time. If the timer reaches zero the timer is stopped, the cards can no longer be clicked, and an alert is sent to the browser.

stopTime()

This stops the countdown of the timer. This is called when all the cards are matched or when the timer reaches 0:00.