0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

JavaScriptでビンゴゲームを作ってみた

Last updated at Posted at 2021-03-27

JavaScriptでビンゴゲームを作ってみました。

#仕様

  • カードは25マス。
  • 「CARD SET」を押すと,カードにランダムな数字が入る。「CARD SET」は無効化する。
  • 「CHOOSE NUMBER」を押すと,ランダムな数字が結果として表示される。
  • 結果と一致するカードのマスは色が変わる。
  • 履歴欄に結果の数字を順番に追加していく。
  • 全ての数字を選び終わると,アラートで終了を知らせる。「CHOOSE NUMBER」は無効化する。
  • 「RESET」を押すと,最初の状態に戻る。

↓最初の画面
bingo_img2.png
↓ビンゴ中の画面
bingo_img3.png

#コード

####HTML

index.html
<!DOCTYPE html>
<html lang="ja">
<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <meta http-equiv="X-UA-Compatible" content="ie=edge">
   <title>ビンゴゲーム | JS</title>
   <link rel="preconnect" href="https://fonts.gstatic.com">
   <link href="https://fonts.googleapis.com/css2?family=Goldman&family=Press+Start+2P&display=swap" rel="stylesheet">   
   <link rel="stylesheet" href="styles/style.css"/>
</head>
<body>
   <h1 class="title">!!!!! BINGO GAME !!!!!</h1>
   <div class="container">
      <div class="left-container">
         <div class="left-container__btns">
            <button id="setBtn" class="btn">CAED SET</button>
            <button id="chooseBtn" class="btn">CHOOSE NUMBER</button>
            <button id="resetBtn" class="btn">RESET</button>
         </div>
         <div class="left-container__roulette" id="roulette">
         </div>
         <div class="left-container__history">
            <h2>HISTORY_</h2>
            <ul class="history-list" id="history-list"></ul>
         </div>
      </div>
      <div class="card-container">
         <h2>CARD</h2>
         <div id="card">
         </div>
      </div>
   </div>
   
<script src="scripts/selectNumber.js"></script>
<script src="scripts/main.js"></script>
</body>
</html>

####CSS(SCSS)

SCSS
styles/style.scss
$cWhite: #ffffff;
$cYellow: #f8cc2f;
$cBlackGray: #2c2c2c;
$cRed: #e00000;
$cGreen: #03a305;
$cGray: rgb(192, 191, 191);

body {
	margin: 0;
	text-align: center;
	background-color: $cYellow;
	width: 100vw;
	height: 100vh;
	box-sizing: border-box;
	position: relative;
}

.title {
	font-family: 'Press Start 2P', cursive;
	color: $cRed;
	font-size: 2rem;
	text-shadow: 3px 3px 0px $cWhite;
}

.container {
	width: 90%;
	margin: 0 auto;
	padding-top: 20px;
	max-width: 1000px;
	display: flex;
	justify-content: space-between;
	align-items: center;
}

.left-container {
	width: 48%;

	&__btns {
		display: flex;
		flex-direction: column;
	
		& .btn {
			display: inline-block;
			box-sizing: border-box;
			padding-top: 15px;
			padding-bottom: 15px;
			margin: 15px 0;
			width: 100%;
			background-color: #04c706;
			border: outset 6px $cGreen;
			outline: none;
			font-size: 18px;
			color: $cWhite;
			font-family: 'Press Start 2P', cursive;
			cursor: pointer;
			
			&:disabled {
				background-color: rgb(172, 172, 172);
				color: $cWhite;
				border: inset 6px $cGray;
			}
		}
	}

	&__roulette {
		display: flex;
		justify-content: center;
		align-items: center;   
		box-sizing: border-box;
		margin: 15px auto;
		width: 200px;
		height: 120px;
		background-color: $cWhite;
		border: solid 6px $cRed;
		border-radius: 50%;
		font-size: 42px;
		font-family: 'Press Start 2P', cursive;
		color: $cRed;
	}

	&__history {
		box-sizing: border-box;
		padding: 20px;
		width: 100%;
		height: 180px;
		background-color: $cBlackGray;
		border: solid 3px $cWhite;
		
		& h2 {
			margin: 0;
			text-align: left;
			font-family: 'Press Start 2P', cursive;
			font-size: 18px;
			color: $cWhite;
		}
		
		& ul {
			margin: 0 auto;
			padding: 10px 0 0 0;
			font-family: 'Press Start 2P', cursive;
			color: $cWhite;
			list-style: none;
			display: flex;
			flex-wrap: wrap;
			
			& li {
				width: 12%;
				font-size: 0.8rem;
				line-height: 1.5rem;
			}
		}
	}
}

.card-container {
	width: 48%;
	height: 600px;
	background-color: $cWhite;
	box-shadow: 9px 9px 0px $cBlackGray;
	
	& h2 {
		margin: 35px auto;
		padding-left: 0.7em;
		font-family: 'Press Start 2P', cursive;
		font-size: 35px;
		color: $cBlackGray;
		letter-spacing: 0.7em;
	}

	& #card {
		margin: 20px;
		width: 90%;
		display: flex;
		flex-wrap: wrap;

		& .cell {
			box-sizing: border-box;
			width: 20%;
			background-color: $cWhite;
			border: solid 3px $cGray;
			position: relative;
			
			&::before {
				content: '';
				display: block;
				padding-top: 100%;
			}
			
			& .cell-inner {
				font-family: 'Press Start 2P', cursive;
				display: flex;
				justify-content: center;
				align-items: center;
				position: absolute;
				top: 0;
				left: 0;
				width: 100%;
				height: 100%;
				font-size: 1.2rem;
				color: $cBlackGray;
			}
	
			&.opened {
				background-color: $cRed;
				& .cell-inner {
					color: $cWhite;
				}
			}
		}
	}
}

####JavaScript

scripts/selectNumber.js
class SelectNumber {
   constructor(arrBox) {
      this.arrBox = arrBox;
      this.arr = [];
      this._setNumber();
      this._assignNumber(arrBox);
   }
   _setNumber() {
      for(let i = 1; i <= 75; i++) {
         this.arr.push(i);
      }
   }
   _assignNumber() {
      for(let j = 0, len = this.arr.length; j < 25; j++, len--) {
         let rdmNumber = Math.floor(Math.random() * len);
         this.arrBox.push(this.arr[rdmNumber]);
         this.arr[rdmNumber] = this.arr[len - 1];
      }
   }
}
scripts/main.js
window.addEventListener('DOMContentLoaded', function() {
   
   const card = document.getElementById('card');
   const setBtn = document.getElementById('setBtn');
   const chooseBtn = document.getElementById('chooseBtn');
   const roulette = document.getElementById('roulette');
   const historyList = document.getElementById('history-list');
   const resetBtn = document.getElementById('resetBtn');
   
   let countClick = 0;
   let cardArr = [];
   let resultArr = [];
   setBtn.disabled = false;
   chooseBtn.disabled = false;

   setBtn.addEventListener('click', function() {
      const select1 = new SelectNumber(cardArr);
      const select2 = new SelectNumber(resultArr);

      for (let i = 0; i < 25; i++) {
         const cell = document.createElement('div');
         const cellInner = document.createElement('div');
         cell.classList.add('cell');
         cellInner.classList.add('cell-inner');
      
         cellInner.textContent = cardArr[i];
         cell.setAttribute('name', cardArr[i]);
      
         cell.appendChild(cellInner);
         card.appendChild(cell);
      };

      setBtn.disabled = true;
   });
   
   chooseBtn.addEventListener('click', function() {
      if(countClick === 25) {
         alert('FINISH!!!!');
         chooseBtn.disabled = true;
      } else {
         const result = resultArr[countClick];
         roulette.textContent = result;
         
         const li = document.createElement('li');
         li.textContent = result;
         historyList.appendChild(li); 

         const resultCell = document.querySelector(`.cell[name = "${result}"]`);
         if(resultCell !== null) {
            resultCell.classList.add('opened');
         }
         
         countClick++;
      }  
   }); 

   resetBtn.addEventListener('click', function() {
      window.location.reload();
   });
});

#解説

####ランダムな数字を選ぶ

scripts/selectNumber.js
class SelectNumber {
   constructor(arrBox) {
      this.arrBox = arrBox;
      this.arr = [];
      this._setNumber();
      this._assignNumber(arrBox);
   }
   _setNumber() {
      for(let i = 1; i <= 25; i++) {
         this.arr.push(i);
      }
   }
   _assignNumber() {
      for(let j = 0, len = this.arr.length; j < 25; j++, len--) {
         let rdmNumber = Math.floor(Math.random() * len);
         this.arrBox.push(this.arr[rdmNumber]);
         this.arr[rdmNumber] = this.arr[len - 1];
      }
   }
}

1〜75のランダムな数字を選ぶclass。
正確には,1〜75の中から25個を重複なくランダムに選び,渡された配列に順に格納していくclass。
今回はこのclassで,「カード用の配列」と「結果用の配列」を作成。

この仕組みは何方かのブログで見つけ利用させて頂いたのですが,この記事を書くためにもう一度探したら見当たりませんでした。見つけ次第記載します。申し訳ありません…

####「CARD SET」を押した時の動作

scripts/main.js
setBtn.addEventListener('click', function() {
      const select1 = new SelectNumber(cardArr);
      const select2 = new SelectNumber(resultArr);

      for (let i = 0; i < 25; i++) {
         const cell = document.createElement('div');
         const cellInner = document.createElement('div');
         cell.classList.add('cell');
         cellInner.classList.add('cell-inner');
      
         cellInner.textContent = cardArr[i];
         cell.setAttribute('name', cardArr[i]);
      
         cell.appendChild(cellInner);
         card.appendChild(cell);
      };

      setBtn.disabled = true;
});
  • 「カード用の配列」と「結果用の配列」を準備する。
  • カードのマスになるHTMLを組み立てる。
  • この後で選ばれたマスの表示を変えるのに使う為,cellに自分の番号のname属性を付けておく。
  • 「CARD SET」は無効化する。

####「CHOOSE NUMBER」を押した時の動作

scripts/main.js
chooseBtn.addEventListener('click', function() {
      if(countClick === 25) {
         alert('FINISH!!!!');
         chooseBtn.disabled = true;
      } else {
         const result = resultArr[countClick];
         roulette.textContent = result;
         
         const li = document.createElement('li');
         li.textContent = result;
         historyList.appendChild(li); 

         const resultCell = document.querySelector(`.cell[name = "${result}"]`);
         if(resultCell !== null) {
            resultCell.classList.add('opened');
         }
         
         countClick++;
      }  
}); 
  • if文でクリック数を監視。
  • 結果用の配列の「クリック数」番目の数字を結果として表示する。
  • 履歴欄に結果の数字を追加。
  • 結果と一致するname属性値を持つcellを取得→classの追加で表示変更。
  • 25回クリックしていたら(26回目を押したら),「FINISH!!!!」のアラートが出る。
  • 「CHOOSE NUMBER」を無効化。

####(2021/3/28更新 改善)

  • 数字がランダムで選ばれる範囲:25→75に変更
  • 結果と一致するname属性値を持つcellが,card上に存在するかif文で調べる。存在すれば(resultCellがnullではなければ)classを追加。

#反省,改善点

  • 数字を選ぶ際に,ドラムロール式にしたかった。
  • カードのリセットがページを再読み込みする方法になっている。それぞれの要素をリセットするような方法にしたい。(どっちの方が負担や効率面で良いのか分かりませんが…)
0
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?