理系公務員のプログラミング日記

JavaScriptでビンゴゲーム① ビンゴカードの作成

タグ:
JavaScript

ビンゴゲーム

今回はビンゴゲームをJavaScriptで実装してみます。

少し考えることは多くなりますが、基本は

  • ・必要な機能(ロジック)を可能な限り分解してシンプルに考えること。
  • ・シンプルにした機能を実装し動作確認(テスト)をすること。
  • ・それを一つずつ積み上げること。

が中心です。

難しい!書けない!となっているときは、一度に複数のことをドカンと実装しようとしているかもしれません。一つずつ少しずつコツコツと実装しましょう。

参考:コピペするプログラマに足りないもの 〜 プログラミング脳の鍛え方

ビンゴゲームに必要な要素

ビンゴゲームのうち、各参加者に配られるビンゴカードに必要な要素を考えます。

  1. カードが配られたら(画面がロードされたら)、1〜99までのランダムな数字が25個表示される。
  2. ビンゴゲームの進行に合わせて数字をチェックしていく。今回は外部で指定された数字をクリックしていくことにする。
  3. ゲームの進行に合わせてカードをチェックし、ビンゴを判定して表示する。

1. 1〜99までのランダムな数字を25個表示する

まずは見た目の部分であるビンゴカードを実装します。
流れとしてはこんな感じ

  • a.マス目を25個作成する。
  • b.各マス目のtextContentにランダムな数値を代入する。

まず1を実装します。数値は適当に1で良いでしょう。

HTML

<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> .bingocard { display: grid; /* gridは5列になるように設定する */ grid-template-columns: repeat(5,1fr); width: 500px; margin: 20px; } .bingocard div { height: 100px; width: 100px; text-align: center; line-height: 90px; border: 1px solid black; font-size: 30px; } </style> </head> <body> <div class="bingocard"> </div> </body> <script src="./bingo.js"></script> </html>

a.マス目を25個作成する。

ファイル名を"bingo.js"として、htmlから読み込んでいます。

makeMasuはdocument.createElement("div")でdiv要素を作ります。
その次にmasu.textContentで文字要素を追加します。
最後に、document.querySelector(".bingocard")でdiv要素を追加する先の親要素を指定し、.appendChild()で作成したdiv要素を追加しました。

以上の内容をforループによって25個作成しました。

この bingocard クラスにはcssで横が5列になるようにgrid-template-columnsを指定しています。

const makeMasu = () => { const masu = document.createElement("div"); masu.textContent = 1 document.querySelector(".bingocard").appendChild(masu) } for (let i = 0; i < 25; i++) { makeMasu(); }

ビンゴ1

b.各マス目のtextContentにランダムな数値を代入する。

次に2である数値にランダムな値を入れます。

Math.random() は0~1までの数値をランダムに生成する。 これを100倍することで、0~100までの数値(少数を含む)をランダムに生成することができます。

Math.floor()は少数を切り捨て処理によって整数にすることができます。

この2つを組み合わせることで、0〜100までの整数をランダムに生成しています。

const makeMasu = () => { const masu = document.createElement("div"); masu.textContent = Math.floor(Math.random()*100) document.querySelector(".bingocard").appendChild(masu) } for (let i = 0; i < 25; i++) { makeMasu(); }

ビンゴ2

2.ビンゴゲームの進行に合わせて数字をチェックしていく。

次に、ビンゴゲームを進行させていく上で必要な機能を実装します。

a.各マス目にclickイベントを追加する。 b.クリックしてゲームが進行していく状況を配列で表現する。

a.各マス目にclickイベントを追加する。

追加するdiv要素にclickイベントを追加します。
addEventListener("click",(evt)=>{})ではイベントオブジェクトをevtと名付けた引数に格納しています。
イベントオブジェクトには発生したイベントの情報が格納されており、ここではevt.targetでclickイベントを発生させた要素を指定しました。

const makeMasu = () => { const masu = document.createElement("div"); masu.textContent = Math.floor(Math.random()*100) masu.addEventListener("click",(evt)=>{ evt.target.textContent = "◯"; }) document.querySelector(".bingocard").appendChild(masu) } for (let i = 0; i < 25; i++) { makeMasu(); }

ビンゴ3

b.クリックしてゲームが進行していく状況を配列で表現する。

盤面の数字を配列に覚えさせます。

randomNumber定数に生成したランダムな値を覚えさせます。
コードの頭で生成した空のcheckList配列に生成したランダムな値をpushメソッドで追加していきます。
randomNumberはtextContentの設定にも利用します。

なお、checkList配列は1次元で作る場合と2次元とする場合と2パターン考えられます。
この記事では1次元で作成してみます。

checkList = []; const makeMasu = () => { const masu = document.createElement("div"); const randomNumber = Math.floor(Math.random()*100); checkList.push(randomNumber); masu.textContent =randomNumber; masu.addEventListener("click",(evt)=>{ evt.target.textContent = "◯"; }) document.querySelector(".bingocard").appendChild(masu); } for (let i = 0; i < 25; i++) { makeMasu(); }

ビンゴ4

次に、clickイベントが発生したときにchecklist配列を変更するようにします。
イベント内のコールバック関数にcheckListを変更する処理を書くことで、クリックで配列が変更されるようになります。

コールバック関数内でcheckListの要素を指定するには、checkListのどの要素かを指定してやる必要があります。
forループのイテレーターiを引数として受け取り、マスをクリックしたときに対応している配列の要素を変更できるようにしました。

checkList = []; const makeMasu = (i) => { const masu = document.createElement("div"); const randomNumber = Math.floor(Math.random()*100); checkList.push(randomNumber); masu.textContent =randomNumber; masu.addEventListener("click",(evt)=>{ evt.target.textContent = "◯"; checkList[i] = "◯" // 期待通りにcheckListが動いているか確認 console.log(checkList) }) document.querySelector(".bingocard").appendChild(masu); } for (let i = 0; i < 25; i++) { makeMasu(i); }

ビンゴ5

(別解)

new Array(25).fill(0)で長さ25の配列を生成して、そこにランダムな値を追加していっても良いと思います。

checkList = new Array(25).fill(0) const makeMasu = (i) => { const masu = document.createElement("div"); const randomNumber = Math.floor(Math.random()*100); checkList[i] = randomNumber; masu.textContent =randomNumber; // (以下略) }

数字の置き方を実際の仕様に合わせる

bingoゲームの数字は1列目は1~15,2列目は16~30,3列目は31~45,4列目は46~60,5列目は61~75となっています。

この仕様を反映させましょう。

列(縦方向)ごとに乱数の生成の仕方を調整したいですが、ビンゴカードの値が入っている配列は行(横方向)に並んでおり、そのままでは扱いにくいです。

列方向で要素を取り出す方法を考えると、各コマの番号を5で割った余りを使うことを思いつきました。

各コマの番号(iの値)はこんな感じです。

ビンゴ6

5で割った余りを出すとこうなります。

ビンゴ7

checkList = [] const makeMasu = (i) => { const masu = document.createElement("div"); // コマの番号を5で割った余りからどの列かを出す const col = i % 5; const randomNumber = Math.floor(Math.random() * 15 + col * 15 + 1); checkList.push(randomNumber); masu.textContent = randomNumber; masu.addEventListener("click", (evt) => { evt.target.textContent = "◯"; checkList[i] = "◯" // 期待通りにcheckListが動いているか確認 console.log(checkList) }) document.querySelector(".bingocard").appendChild(masu); } for (let i = 0; i < 25; i++) { makeMasu(i); }

ビンゴ8