JavaScript - 神経衰弱ゲームの作り方 Part 1 - カードをシャッフルする

カードを生成して数字を割り振ろう

JavaScript で神経衰弱ゲームを作る方法を、2回に分けて解説します。今回作る神経衰弱は、カードを2枚クリックして数字を揃えていくゲームです。

  • Part 1(この記事)では、ゲームに使うカードを用意します。カードは JavaScript で生成し、そのカードに数字をランダムに割り振ります。ゲームを開始するたびに数字の位置が変わるようにすることで、カードをシャッフルします。
  • Part 2 では、カードをクリックしてめくれるようにし、数字が揃ったかどうかをチェックします。全部を揃え終わったら自動的にカードをリセットし、繰り返し遊べるようにコーディングします。

この記事を読むと分かること

  • querySelector()
  • querySelectorAll()
  • document.createElement()
  • classList.add()
  • appendChild()
  • forEach()
  • for ループ
  • 配列
  • Fisher-Yates アルゴリズム(配列のシャッフル)

サンプルプロジェクト

最初に、神経衰弱ゲームの動きを確認しておきましょう。

  • クリックでカードをめくる
  • 一度にめくれるのは2枚まで
  • 数字が揃ったら、そのカードはクリックに反応しなくなる
  • 数字が揃わなかったら、カードは伏せられる
メモリーゲームのサンプル

HTML と CSS

まずは HTML です。今回は、JavaScript でカードを生成します。生成したカードを表示するエリア(ゲームコンテナ)を <div> 要素で用意しておきましょう。

<div class="wrapper">
  <h1>Memory Game</h1>

  <!-- ゲームコンテナ -->
  <div class="game-container"></div>

</div>

続いて CSS です。カードを並べて伏せてあるときの見た目(数字は見えない状態)のほかに、カードをめくったときの見た目(数字が見える状態)のクラス show を用意します。これは、この後の JavaScript で CSS クラスの付け外しをして、カードを裏返すために必要になります。

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100vw;
  height: 100vh;
  background-color: lightgray;
}

h1 {
  text-align: center;
}

.game-container {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  width: 500px;
}

/* カードを伏せてあるときの見た目 */
.game-card {
  width: 100px;
  height: 100px;
  color: transparent;        /* 数字は透明にして見えなくする */
  background-color: #4FA0F8; /* カードは青色 */
  display: flex;
  font-size: xx-large;
  font-weight: bold;
  align-items: center;
  justify-content: center;
  border: 2px solid black;
  border-radius: 10px;
  cursor: pointer;
  margin:3px;
  -webkit-user-select: none;
  user-select: none;
}

/* カードをめくったときの見た目 */
.show {
  color: black;            /* 数字を黒にする */
  background-color: white; /* カードを白にする */
}

JavaScript

さて、次は JavaScript です。今回の Part 1 では、ゲームに使うカードを作成していきます。カードのシャッフルは、カードの位置を変更するのではなく、割り振る数字をランダムに変更することで表現しますよ。

配列と変数

最初に数字を用意しましょう。今回作る神経衰弱ゲームは数字を揃えるゲームなので、数字をペアで配列 numbers に格納します。

// 数字をペアで格納した配列
const numbers = [1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6];

配列に保存した数字(要素)の数 numbers.length は、この後のコードで利用します。変数で参照できるように、cardNumbers に入れておきましょう。

const numbers = [1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6];

// 配列の要素数
const cardNumbers = numbers.length;

続いてはカードです。後で生成する複数のカードを格納するための変数 cards を宣言します。最初は空っぽであることを示すために、null で初期化してください。

const numbers = [1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6];
const cardNumbers = numbers.length;

// カード
let cards = null;

カードを生成する - createCards

配列と変数を用意できたら、カードを生成しましょう。カードを生成する処理を、関数 createCards として定義していきますよ。

// カードを生成する
function createCards() {

  // 1. ゲームコンテナを取得する
  // 2. 配列の要素数と同じだけ繰り返してカードを生成する
  // 3. すべてのカードを変数に格納する

}

1. ゲームコンテナを取得する

まずは、カードを配置する場所となるゲームコンテナを取得して、変数 gameContainer で参照できるようにしておきます。

  • ゲームコンテナを querySelector() メソッドで取得し、変数 gameContainer に格納します。
function createCards() {

  // 1. ゲームコンテナを取得する
  const gameContainer = document.querySelector('.game-container');

  // 2. 配列の要素数と同じだけ繰り返してカードを生成する
  // 3. すべてのカードを変数に格納する

}

2. 配列の要素数と同じだけ繰り返してカードを生成する

ここからが、実際にカードを作る処理です。カードは、for 文の繰り返しで生成します。作るカードの枚数は、配列に格納してある数字と同じ数です。

  • カードを生成する処理を、配列の要素数 cardNumbers と同じ数だけ繰り返します。
function createCards() {
  const gameContainer = document.querySelector('.game-container');

  // 2. 配列の要素数と同じだけ繰り返してカードを生成する
  for (let i = 0; i < cardNumbers; i++) {

    // カードを生成する処理
    // …

  }

  // 3. すべてのカードを変数に格納する

}

for 文について詳しくは以下の記事をご覧ください。

JavaScript - for ループ (繰り返し) の基本【初心者向け】
繰り返し処理を実行するために使われる for 文の書き方や、ループの中で使われる break 文と continue 文について、プログラミング初心者の方でも分かりやすいように簡単なコードを例にして解説します。

for 文の中身となる「カードを生成する処理」を書いていきましょう。

  • document.createElement() メソッドで <div> 要素を生成し、変数 card に格納します。この <div> 要素一つひとつがカードになります。
function createCards() {
  const gameContainer = document.querySelector('.game-container');

  // 2. 配列の要素数と同じだけ繰り返してカードを生成する
  for (let i = 0; i < cardNumbers; i++) {

    // カード(div要素)を生成する
    const card = document.createElement('div');

  }

  // 3. すべてのカードを変数に格納する

}
  • 生成したカード(<div> 要素)に、classList.add() メソッドで game-card クラスを追加します。これによって、CSS で指定したカードの見た目が設定されます。
function createCards() {
  const gameContainer = document.querySelector('.game-container');

  // 2. 配列の要素数と同じだけ繰り返してカードを生成する
  for (let i = 0; i < cardNumbers; i++) {
    const card = document.createElement('div');

    // クラスを追加する(カードの見た目を設定)
    card.classList.add('game-card');

  }

  // 3. すべてのカードを変数に格納する

}
  • 生成したカード(<div> 要素)を、appendChild() メソッドでゲームコンテナに追加します。
function createCards() {
  const gameContainer = document.querySelector('.game-container');

  // 2. 配列の要素数と同じだけ繰り返してカードを生成する
  for (let i = 0; i < cardNumbers; i++) {
    const card = document.createElement('div');
    card.classList.add('game-card');

    // ゲームコンテナにカード(div要素)を追加する
    gameContainer.appendChild(card);
  }

  // 3. すべてのカードを変数に格納する

}

ここまでで、カードを12枚作るコードができました。

3. すべてのカードを変数に格納する

生成したすべてのカードをまとめて参照できるよう、変数 cards に保存しましょう。

  • すべてのカードを querySelectorAll() メソッドで取得し、変数 cards に格納します。
function createCards() {
  const gameContainer = document.querySelector('.game-container');
  for (let i = 0; i < cardNumbers; i++) {
    const card = document.createElement('div');
    card.classList.add('game-card');
    gameContainer.appendChild(card);
  }

  // 3. すべてのカードを変数に格納する
  cards = document.querySelectorAll('.game-card');
}

以上で、カードを生成する関数 createCards を定義できました。関数 createCards を呼び出すと、ブラウザには以下のように表示されますよ。

縦3横4の合計12枚のカードが並んでいる

配列の数字をシャッフルする - shuffleNumbers

カードを生成したら、今度は、そこに表示する数字を用意します。

神経衰弱が楽しいのは、どこにどの数字が隠れているのかが分からないところですよね。そのためには、配列内に順番にまとめた数字をシャッフルして、ランダムに並べ替える必要があります。配列内の要素をランダムに並べ替えたいときは、Fisher-Yates アルゴリズムを使用すると偏りのないシャッフル結果を得ることができますよ。

// Fisher-Yatesアルゴリズムを利用したシャッフル

// 配列の数字をランダムに並び替える(シャッフルする)
// 配列の最後の要素(i番目)から繰り返し処理を始める
for (let i = cardNumbers - 1; i > 0; i--) {
  // 0からi番までのランダムなインデックス(番号)を取得してjに格納する
  const j = Math.floor(Math.random() * (i + 1));
  // i番目(現在処理中)の要素とj番目の要素を置き替える
  [numbers[i], numbers[j]] = [numbers[j], numbers[i]];
}

すべてのカードに数字を割り振る

ランダムに並べ替えた数字を、生成したカードに割り振りましょう。「数字を割り振る」という処理をカード1枚1枚に行うために、forEach() メソッドを使用します。

  • cards:生成したすべてのカードを参照します。
  • forEach():すべてのカードに対して処理を行います。
  • card:処理の対象となっているカードを表す変数です。
  • i:処理の対象となっているカードのインデックス(番号)を表します。
for (let i = cardNumbers - 1; i > 0; i--) {
  const j = Math.floor(Math.random() * (i + 1));
  [numbers[i], numbers[j]] = [numbers[j], numbers[i]];
}

// すべてのカードに数字を割り振る
cards.forEach((card, i) => {

  // 数字を割り振る

});

forEach() メソッドで実行する文を書きましょう。シャッフルした配列から一つずつ数字を取得して、カードに表示されるようにしますよ。

  • numbers[i]と書くと、処理中のカードと同じインデックス(i)に対応する数字を、配列 numbers から取得することができます。その値を、処理中のカードのtextContent プロパティに代入します。
for (let i = cardNumbers - 1; i > 0; i--) {
  const j = Math.floor(Math.random() * (i + 1));
  [numbers[i], numbers[j]] = [numbers[j], numbers[i]];
}

cards.forEach((card, i) => {

  // 数字を割り振る
  card.textContent = numbers[i]

});

以上で、配列の数字をシャッフルし、すべてのカードに割り振るコードができました。このコードは、神経衰弱ゲームを繰り返し楽しむために、簡単に再利用できるようにします。shuffleNumbers という名前で関数にまとめておきましょう。

// 数字をシャッフルしてすべてのカードに割り振る
function shuffleNumbers() {

  // 配列の数字をシャッフルする
  for (let i = cardNumbers - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [numbers[i], numbers[j]] = [numbers[j], numbers[i]];
  }
  // すべてのカードに数字を割り振る
  cards.forEach((card, i) => {
    card.textContent = numbers[i]
  });

}

では、ここまで書いたコードで数字がどのように表示されるのかを試してみます。ただ、現在のカードは伏せられた状態(数字が透明で見えない)なので、CSS で用意した show クラスをお試しで追加してから実行してみましょう。

お試し表示:

const numbers = [1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6];
const cardNumbers = numbers.length;
let cards = null;

function createCards() {
  const gameContainer = document.querySelector('.game-container');
  for (let i = 0; i < cardNumbers; i++) {
    const card = document.createElement('div');
    card.classList.add('game-card');
    
    //----------- お試し表示 ----------
    card.classList.add('show'); // カードの背景色を白、文字を黒にする
    //--------------------------------
    
    gameContainer.appendChild(card);
  }
  cards = document.querySelectorAll('.game-card');
}

function shuffleNumbers() {
  for (let i = cardNumbers - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [numbers[i], numbers[j]] = [numbers[j], numbers[i]];
  }
  cards.forEach((card, i) => {
    card.textContent = numbers[i]
  });
}

// カードを生成し、数字を割り振る
createCards();
shuffleNumbers();

結果は下のようになります。コードを再実行するたびに、どこにどの数字が表示されるかはランダムに変わりますよ。

カードに割り振られた数字の表示例

Part 1 で解説した全コード

神経衰弱ゲームの作り方 Part 1 はここまでとなります。解説してきた全コードを下にまとめました。

// カードをシャッフルするコード

// 使用する数字
const numbers = [1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6];
// 数字の数
const cardNumbers = numbers.length;
// 初めはカード無し
let cards = null;

// カードを生成する
function createCards() {
  const gameContainer = document.querySelector('.game-container');
  for (let i = 0; i < cardNumbers; i++) {
    const card = document.createElement('div');
    card.classList.add('game-card');
    gameContainer.appendChild(card);
  }
  // 生成したすべてのカードを変数に格納
  cards = document.querySelectorAll('.game-card');
}

// 配列の数字をシャッフルする
function shuffleNumbers() {
  for (let i = cardNumbers - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [numbers[i], numbers[j]] = [numbers[j], numbers[i]];
  }
  // すべてのカードに数字を割り振る
  cards.forEach((card, i) => {
    card.textContent = numbers[i]
  });
}

createCards();
shuffleNumbers();

最後に、下の CodePen で実際に遊んでみてください。

See the Pen JavaScript - Memory Game by Pyxofy (@pyxofy) on CodePen.


まとめ

今回は、JavaScript で神経衰弱ゲームを作る方法の Part 1 として、カードをシャッフルするコードを紹介しました。

カードは HTML で用意することもできますが、ここでは JavaScript の document.createElement() メソッドで生成しました。カードに何の数字が隠れているかを分からなくするために、Fisher-Yates アルゴリズムを利用して配列の数字をシャッフルできるようにしたので、何度でもゲームを楽しむことができますよ。Part 2 では、カードをクリックしてめくれるようにしてゲームを完成させます。お楽しみに!

最後まで読んでいただき、ありがとうございます。この記事をシェアしてくれると嬉しいです!

SNSで Pyxofy とつながりましょう! LinkedInThreadsMastodon X (Twitter) @pyxofyFacebook

関連記事

JavaScript - パスワード生成アプリの作り方
ランダムなパスワードを生成するアプリを JavaScript で作ります。数字や記号をパスワードに含めるかどうかを選べたり、パスワードの長さを自由に変えられる、そんなアプリを一緒に作ってみましょう。
CSS Art - How to Make Shadows and Angles
We will learn how to implement HTML and text shadows in CSS. Then we’ll explore how to make right, obtuse and acute angles in this article.
CSS Animation – How to Make a Sunrise with @property – Part 1
Sunrises are majestic. They cast multiple shades of color and beautiful gradients. You’ll learn how to create one in this step-by-step article.
スクラッチプログラミング - じゃんけんゲームのつくりかた
コンピューターとじゃんけんをするプログラムをつくってみましょう。「コスチューム」と「メッセージ」のブロックをつかって、グーチョキパーで勝負(しょうぶ)できるようにプログラミングします。