Simple Memory Game in Vanilla Javascript (Free Download)

Welcome to a beginner’s tutorial on how to create a simple memory game in Javascript. Interested to learn how to create browser games in Javascript? Or looking for a simple project to do? Then the class memory game is a good place to get started since it is not too complicated – Read on to find out!

ⓘ I have included a zip file with all the example source code at the start of this tutorial, so you don’t have to copy-paste everything… Or if you just want to dive straight in.

 

TABLE OF CONTENTS

Download & Demo How It Works Useful Bits & Links
The End

 

 

DOWNLOAD & NOTES

Firstly, here is the download link to the example code as promised.

 

QUICK NOTES

If you spot a bug, feel free to comment below. I try to answer short questions too, but it is one person versus the entire world… If you need answers urgently, please check out my list of websites to get help with programming.

 

EXAMPLE CODE DOWNLOAD

Click here to download the source code, I have released it under the MIT license, so feel free to build on top of it or use it in your own project.

 

MEMORY GAME DEMO

 

 

HOW IT WORKS

All right, let us now get into more details on the mechanics of how the memory game.

 

PART 1) THE HTML

memory.html
 <div id="mem-game"></div>

HTML is the easiest component, we will use Javascript to generate the <img> cards into <div id="mem-game">. That’s all.

 

PART 2) THE CSS

memory.css
/* (A) CONTAINER */
#mem-game {
  display: grid;
  grid-template-columns: auto auto auto auto;
  grid-gap: 10px;
  max-width: 420px;
  margin: 0 auto;
}

/* (B) CARDS */
.mem-card {
  padding: 10px;
  cursor: pointer;
  background: #e5e5e5;
}
.mem-card.open { background: #fea; }
.mem-card.right { background: #b3ffc0; }
.mem-card.wrong { background: #ffb6b6; }
  • The important part here is essentially display: grid and grid-template-columns: auto auto auto auto. CSS literally does the rest of the layout magic.
  • The rest are kind of self-explanatory too.
    • .mem-card.open is the style for opened cards.
    • .mem-card.right for cards that are correctly matched.
    • .mem-card.wrong for cards that are wrongly matched.

 

 

PART 3) BASIC JAVASCRIPT MECHANICS

memory.js
var mem = {
  // (A) PROPERTIES
  // (A1) HTML ELEMENT
  hWrap : null, // html game wrapper
 
  // (A2) GAME SETTINGS & FLAGS
  url : "https://code-boxx.com/wp-content/uploads/2019/08/", // optional,
  moves : 0, // total number of moves url to images
  sets : 6, // number of sets to match
  grid : [], // current game grid
  matched : 0, // number of sets that have been matched
  last : null, // last opened card
  lock : null, // timer, lock game controls when showing mismatched cards
  hint : 1000, // how long to show mismatched cards
  // ...
}
  • Captain Obvious, var mem holds all the game mechanics.
  • There are quite a number of flags, but the essentials are:
    • mem.sets We define the total number of sets to pair.
    • Since there are 6 images in this example, mem.grid will be an array of 12 (randomly shuffled) HTML images to pair.
    • As the player matches a pair correctly, we track it with mem.matched; When mem.matched == mem.sets, the game ends.

 

PART 4) PRELOAD IMAGES

memory.js
// (B) PRELOAD
preload : () => {
  // (B1) GET HTML GAME WRAPPER
  mem.hWrap = document.getElementById("mem-game");
 
  // (B2) PRELOAD IMAGES
  let img, loaded = -1;
  for (let i=0; i<=mem.sets; i++) {
    img = document.createElement("img");
    img.onload = () => {
      loaded++;
      if (loaded == mem.sets) { mem.reset(); }
    };
    img.src = `${mem.url}smiley-${i}.png`;
  }
},
window.addEventListener("DOMContentLoaded", mem.preload);

mem.preload() is the first thing that runs on window load. Shouldn’t be too difficult to understand – We preload all the images before proceeding to start the game.

 

 

PART 5) START/RESTART GAME

memory.js
// (C) RESET GAME
reset : () => {
  // (C1) RESET ALL FLAGS
  clearTimeout(mem.lock); mem.lock = null;
  mem.moves = 0; mem.matched = 0;
  mem.last = null; mem.grid = [];
  for (let s=1; s<=mem.sets; s++) {
    mem.grid.push(s); mem.grid.push(s);
  }
 
  // (C2) RANDOM RESHUFFLE CARDS
  // credits : https://gomakethings.com/how-to-shuffle-an-array-with-vanilla-js/
  let current = mem.sets * 2, temp, random;
  while (0 !== current) {
    random = Math.floor(Math.random() * current);
    current -= 1;
    temp = mem.grid[current];
    mem.grid[current] = mem.grid[random];
    mem.grid[random] = temp;
  }
 
  // (C3) CREATE HTML CARDS
  mem.hWrap.innerHTML = "";
  for (let id in mem.grid) {
    let card = document.createElement("img");
    card.className = "mem-card";
    card.src = `${mem.url}smiley-0.png`;
    card.onclick = () => { mem.open(card); };
    card.set = mem.grid[id];
    card.open = false;
    mem.hWrap.appendChild(card);
    mem.grid[id] = card;
  }
},

Now, this looks confusing, but keep calm and look carefully.

  • (C1) We reset all the game flags. In particular, regenerate mem.grid in running order – [1, 1, 2, 2, 3, 3, ... 6, 6]
  • (C2) Reshuffle mem.grid randomly.
  • (C3) Loop through mem.grid and generate the HTML images.

 

 

PART 6) SELECT A CARD

memory.js
// (D) OPEN A CARD
open : (card) => { if (mem.lock == null) { if (!card.open) {
  // (D1) UPDATE FLAGS & HTML
  card.open = true;
  mem.moves++;
  card.src = `${mem.url}smiley-${card.set}.png`;
  card.classList.add("open");
 
  // (D2) FIRST CARD - SET IN LAST
  if (mem.last == null) { mem.last = card; }
 
  // (D3) SECOND CARD - CHECK MATCH
  else {
    // (D3-1) REMOVE CSS CLASS
    card.classList.remove("open");
    mem.last.classList.remove("open");
 
    // (D3-2) MATCHED
    if (card.set == mem.last.set) {
      // UPDATE FLAGS + CSS
      mem.matched++;
      card.classList.add("right");
      mem.last.classList.add("right");
      mem.last = null;
 
      // END GAME?
      if (mem.matched == mem.sets) {
        alert("YOU WIN! TOTAL MOVES " + mem.moves);
        mem.reset();
      }
    }
 
    // (D3-3) NOT MATCHED - CLOSE BOTH CARDS ONLY AFTER A WHILE
    else {
      card.classList.add("wrong");
      mem.last.classList.add("wrong");
      mem.lock = setTimeout(() => {
        card.classList.remove("wrong");
        mem.last.classList.remove("wrong");
        card.open = false;
        mem.last.open = false;
        card.src = `${mem.url}smiley-0.png`;
        mem.last.src = `${mem.url}smiley-0.png`;
        mem.last = null;
        mem.lock = null;
      }, mem.hint);
    }
  }
}}}

When the player picks a card, a number of things happen.

  • (D1) We set card.open = true to mark the card as “currently open”; Clicking on this card while it is already open does nothing.
  • (D2) Remember this game is about matching pairs? If it is the first opened card, we simply set it into mem.last.
  • (D3) On opening the second card, we check if it matches with mem.last.
    • (D3-2) Increment mem.matched if it is a match, check if the game has ended.
    • (D3-3) If not, we let the cards remain open for a second before closing both of them.

 

 

USEFUL BITS & LINKS

That’s all for this project, and here is a small section on some extras and links that may be useful to you.

 

GAME RULES

For the people who somehow cannot figure the game out…

  • There are a number of “cards” that are scattered randomly across a grid in pairs.
  • The player opens a pair of cards in the grid – If the cards match, that is “one point” and the player will continue to find the next pair.
  • But if the cards don’t match, they will “fold back” to become hidden.
  • The player will have to try to remember all the positions of the cards and match all of them to win.

 

COMPATIBILITY CHECKS

This example will work on all modern “Grade A” browsers.

 

LINKS & REFERENCES

 

THE END

Thank you for reading, and we have come to the end of this guide. I hope that it has helped you with your project, and if you want to share anything with this guide, please feel free to comment below. Good luck and happy coding!

1 thought on “Simple Memory Game in Vanilla Javascript (Free Download)”

Leave a Comment

Your email address will not be published.