Published on

Memory Game using JavaScript

Authors
  • Name
    Andrew Nicholas
    Twitter
Memory Game Preview

Table of Contents

  1. Introduction
  2. Project Structure
  3. HTML Structure
  4. CSS Styling
  5. JavaScript Logic
  6. Images
  7. Running the Game
  8. Conclusion

Introduction

This project is a simple Memory Game created using HTML, CSS, and JavaScript with jQuery. The game involves flipping cards to find matching pairs.

Technologies used include:

  • HTML
  • CSS
  • JavaScript
  • jQuery

Project Structure

Create the Project Structure

  1. Create the project directory and navigate to it:
mkdir memorygame
cd memorygame
  1. Create the following files and directories:
touch index.html main.js memory.css
mkdir images
  1. Download jQuery and jQuery UI:
  • Download the minified versions of jQuery and jQuery UI from their official websites or use the following commands:
curl -o jquery-ui.min.css https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.min.css
curl -o jquery-ui.min.js https://code.jquery.com/ui/1.12.1/jquery-ui.min.js
  1. Add images:
  • Add the card images and 'back.png', 'blank.png' to the 'images' directory.

The project structure should now look like this:

memorygame/
    index.html
    jquery-ui.min.css
    jquery-ui.min.js
    main.js
    memory.css
    images/
        back.png
        blank.png
        card_1.png
        card_2.png
        ...
        card_24.png

HTML Structure

Create the 'index.html' file with the following content:

<!doctype html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Memory Game</title>
    <link type="text/css" rel="stylesheet" href="jquery-ui.min.css" />
    <link type="text/css" rel="stylesheet" href="memory.css" />
  </head>
  <body>
    <header>
      <h1>Memory Game</h1>
      <p id="new_game"><a href="index.html">New Game</a></p>
      <p id="player">&nbsp;</p>
      <p id="high_score">&nbsp;</p>
      <p id="correct">&nbsp;</p>
      <div class="clear"></div>
    </header>
    <main>
      <div id="tabs">
        <ul>
          <li><a href="#tabs-1">Play Game</a></li>
          <li><a href="#tabs-2">View Rules</a></li>
          <li><a href="#tabs-3">Settings</a></li>
        </ul>
        <div id="tabs-1">
          <div id="cards"></div>
        </div>
        <div id="tabs-2">
          <fieldset>
            <legend>How to play the Memory game</legend>
            <ul>
              <li>The cards are placed face down. Each card has a matching card.</li>
              <li>For each turn, the player selects two cards.</li>
              <li>If the cards match, they are removed from the board.</li>
              <li>If the cards don't match, they are turned face down again.</li>
              <li>
                At the end of the game, the player receives a score based on the number of correct
                selections that were made.
              </li>
            </ul>
          </fieldset>
        </div>
        <div id="tabs-3">
          <label for="player_name">Player name:</label>
          <input type="text" id="player_name" /><br />
          <label for="num_cards">Number of cards:</label>
          <select id="num_cards">
            <option>48</option>
            <option>40</option>
            <option>32</option>
            <option>24</option>
            <option>16</option>
            <option>8</option></select
          ><br />
          <input type="button" id="save_settings" value="Save Settings" />
        </div>
      </div>
    </main>
    <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
    <script src="jquery-ui.min.js"></script>
    <script src="main.js"></script>
  </body>
</html>

Explanation:

  • The HTML structure includes a header with the game title and new game link.
  • A main section with tabs for playing the game, viewing rules, and changing settings.
  • A script section to include jQuery and custom JavaScript.

CSS Styling

Create the 'memory.css' file with the following content:

body {
  font-family: Verdana, Arial, Helvetica, sans-serif;
  font-size: 100%;
  background-color: white;
  width: 750px;
  margin: 0 auto;
  border: 3px solid blue;
  padding: 0 2em 1em;
}
h1 {
  font-size: 150%;
  color: blue;
  margin-bottom: 0.5em;
}
label {
  float: left;
  width: 8em;
}
input,
select {
  width: 10em;
  margin-right: 1em;
  margin-bottom: 1em;
}
input[type='checkbox'] {
  width: 2em;
}
header p {
  margin: 0 2em 1em 0;
}
#new_game,
#player,
#high_score,
#correct {
  float: left;
}
#cards img {
  height: 100px;
  width: 80px;
  padding-right: 5px;
  padding-bottom: 3px;
  float: left;
}
.clear {
  clear: both;
}

main {
  border: solid 1px #999;
}

#blocks {
  display: flex;
  background-color: #ddd;
  padding: 10px 0 0 10px;
  margin: 0;
  border-bottom: solid 1px #999;
}

#blocks li {
  display: block;
  list-style: none;
  margin-right: 10px;
  padding: 5px;
  border-top: solid 1px #999;
  border-left: solid 1px #999;
  border-right: solid 1px #999;
  border-radius: 5px 5px 0px 0px;
}

#blocks li a {
  text-decoration: none;
  color: #555;
}

#blocks li a:active {
  text-decoration: none;
  color: antiquewhite;
}

#tabs-1,
#tabs-2,
#tabs-3 {
  padding: 10px;
  margin: 10px;
}
#tabs-1 {
  min-height: 40em;
}

.hidden {
  display: none;
}

.active {
  background-color: #5c5cec;
  color: antiquewhite;
}

#row1,
#row2,
#row3,
#row4,
#row5,
#row6 {
  min-height: 100px;
}

#cards img {
  height: 100px;
  width: 80px;
  padding-right: 5px;
  padding-bottom: 3px;
  float: left;
}
.match {
  pointer-events: none;
}
.flipped1 {
  pointer-events: none;
}
.flipped2 {
  pointer-events: none;
}

.clear {
  clear: both;
}

Explanation:

  • The CSS file defines the styles for the game including the layout, card styles, and responsive design elements.

JavaScript Logic:

Create the 'main.js' file with the following content:

'use strict'

let player_name = ''
let num_cards = 48
let cards
let cards_array = new Array(24)
let matches = 0
let matches_array = new Array()
let num_turns = 0
let highscore = 0

for (let i = 0; i < cards_array.length; i++) {
  cards_array[i] = new Image()
  const card_num = i + 1
  cards_array[i].src = 'images/card_' + card_num.toString() + '.png'
}

const Gameboard = () => {
  num_cards = parseInt(sessionStorage.num_cards)
  if (isNaN(num_cards) || num_cards <= 0) {
    num_cards = 48 // Default value if sessionStorage is not set or invalid
  }

  const num_rows = Math.floor(num_cards / 8)
  let row_string = ''

  let cards = new Array(num_cards)
  for (let num = 0; num < cards.length; num += 2) {
    const card = Math.floor(Math.random() * 24) + 1
    cards[num] = cards_array[card]
    cards[num + 1] = cards_array[card]
  }

  cards.sort(() => Math.random() - 0.5)

  if (num_rows > 0) {
    for (let i = 0; i < num_rows; i++) {
      const x = i + 1
      row_string += `<div id="row` + x.toString() + `"></div>`
    }
    $('#cards').html(row_string)

    let count = 0
    for (let row = 0; row < num_rows; row++) {
      let rows = row + 1
      let card_string = ''
      for (let img = count; img < count + 8; img++) {
        card_string += `<img src="images/back.png" alt=${cards[img].src}>`
      }
      count += 8

      $(`#row${rows}`).html(card_string)
    }
  }
} // End of Gameboard function

$(document).ready(() => {
  $('#tabs').tabs()

  $('#player_name').val(sessionStorage.player_name)
  $('#num_cards').val(sessionStorage.num_cards)
  $('#player').text(sessionStorage.player_name)
  $('#high_score').text(sessionStorage.highscore)

  $('#save_settings').click(() => {
    let isValid = true

    const player_name = $('#player_name').val()
    const num_cards = $('#num_cards').val()
    const highscore = $('#high_score').text()

    if (player_name === '') {
      isValid = false
      alert('Please enter a name.')
    }

    if (isValid) {
      sessionStorage.player_name = player_name
      sessionStorage.num_cards = num_cards
      sessionStorage.highscore = highscore

      location.reload()
    }
  })
  Gameboard()

  let num_flips = 1
  const Flipcard = (card_img) => {
    let game_flip = card_img.attr('alt')
    card_img.attr('class', `flipped${num_flips}`)
    card_img.attr('alt', card_img.attr('src'))
    card_img.attr('src', game_flip)
    matches_array.push(game_flip)
    num_flips += 1
  }

  const Unflipcard = (card_img) => {
    let game_flip = card_img.attr('alt')
    card_img.attr('class', '')
    card_img.attr('alt', card_img.attr('src'))
    card_img.attr('src', game_flip)
  }

  $('img').on('click', function (evt) {
    const delay = 1000
    let card_img = $(this)
    Flipcard(card_img)

    console.log(matches_array)

    if (matches_array.length > 1) {
      if (matches_array[0] === matches_array[1]) {
        console.log('Match!')

        $('.flipped1').attr('class', 'match')
        $('.flipped2').attr('class', 'match')

        $('.match').attr('src', 'images/blank.png')
        num_flips = 1
        matches_array.pop()
        matches_array.pop()
        matches += 1
        num_turns += 1

        let correct = (matches / (num_cards / 2)) * 100
        $('#correct').text(correct)

        if (matches === num_cards / 2) {
          if (num_turns < highscore || highscore === 0) {
            sessionStorage.highscore = num_turns
            console.log(sessionStorage.highscore)
            $('img').css({
              'pointer-events': 'auto',
            })
            $('#high_score').text(sessionStorage.highscore)
          }
        }
      } else {
        console.log('Not a match!')
        $('img').css({
          'pointer-events': 'none',
        })
        setTimeout(function () {
          Unflipcard($('.flipped1'))
          Unflipcard($('.flipped2'))

          $('img').css({
            'pointer-events': 'auto',
          })
        }, delay)
        num_flips = 1
        num_turns += 1

        matches_array.pop()
        matches_array.pop()
      }
    }
    console.log('Turns', num_turns)
  })
})

Explanation:

  • The JavaScript file contains the logic for the memory game.
  • It initializes the game board, handles card flips, checks for matches, and manages game settings.

Adding jQuery

To include jQuery in your project, you can either download the jQuery files or use a CDN (Content Delivery Network).

  1. Using CDN: Add the following script tags in your index.html file inside the head or before the closing body tag:
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script src="jquery-ui.min.js"></script>
<script src="main.js"></script>
  1. Downloading jQuery: You can download the minified version of jQuery and jQuery UI from the official websites:

Images

Add the following images to the images directory:

  • 'back.png'
  • 'blank.png'
  • 'card_1.png to card_24.png'

The images should be used as card faces for the memory game.


Running the Game

To run the game:

  • Open the index.html file in a web browser.
  • Start playing by clicking on the "Play Game" tab.
  • Set your preferences in the "Settings" tab and save them.
  • View the rules in the "View Rules" tab.

Conclusion

This Memory Game project demonstrates how to use HTML, CSS, and JavaScript to create an interactive web application. By following this guide, you can recreate the Memory Game and customize it further to add more features or improve its design.