2021年12月19日
プログラミング
JavaScriptのクラスを使ってビンゴゲームを作る
はじめに
この記事は新しい技術にチャレンジし続けるpalanのアドベントカレンダーDay19の記事です!
昨日は「GLSLを使用した透過動画の実装方法」についての記事でした。
今回はJavaScriptのクラスを使ってビンゴゲームを作成していきます!
ビンゴカード10枚を用意し、3枚がビンゴになった時にゲームが終了するというルールのもと実装していきます。
ビンゴゲームに必要なものとそれぞれの責務
実装に入る前に必要なものとそれぞれの責務を整理していきます。
各クラスの責務を整理してクラス内で必要なメソッドを定義していく事で、影響範囲を最小限に抑えて安全な実装をしていきます。
ビンゴマシーンの責務
- 1~75のランダムな数字を抽選する
- 残数を管理して、同じ数字を出さない
ビンゴカードの責務
- 抽選した数字があれば穴を開ける
- ビンゴがあるかを判定する
- ランダムな数字でビンゴカードを生成
ビンゴマネージャーの責務
- ビンゴカードを10枚生成する
- ランダムな数字を抽選する
- 抽選した数字があれば穴を開ける
- ビンゴがあるかを判定する
- ビンゴカードが10枚中3枚ビンゴになったらゲームを終了する
ビンゴマシーンとビンゴカードのクラスを定義する
ビンゴマシーンの責務
- 1~75のランダムな数字を抽選する
- 残数を管理して、同じ数字を出さない
ビンゴマシーンのクラスを定義する
class BingoMachine {
constructor() {
// 1 ~ 75を持った配列
this.list = new Array(75).fill(null).map((_, i) => i + 1);
}
//毎回ランダムな整数を生成し、生成された値をlistから無くす
drawBingo() {
const index = Math.floor(Math.random() * this.list.length);
const bingo = this.list[index];
this.list.splice(index, 1);
return bingo;
}
}
クラスを定義したら実際にdrawBingoメソッドとlistの挙動がうまく動作しているか確認していきます。
lotteryNumberが55でlistから55が取り除かれているのが確認できると思います。
const lotteryNumber = bingoMachine.drawBingo(); //bingoMachineクラスのインスタンスを生成
console.log(lotteryNumber)
console.log(bingoMachine.list)
ビンゴカードの責務
- ランダムな数字でビンゴカードを生成 ⇨ createCard()
- ビンゴがあるかを判定する ⇨ checkBingo()
- ビンゴがあるかを判定する ⇨ checkBingo()
- 横の列を配列に入れてチェック ⇨ horizontalResult()
- 縦の列を配列に入れてチェック ⇨ verticalResult()
- 斜めの列を配列に入れてチェック ⇨ crossLineResult()
- それぞれの列の配列内の全ての値がfalseかチェック ⇨ isBIngoLine()
ビンゴカードのクラスを定義する
以下の関数で配列の中身が全てfalseなのかをチェックします。
function isBIngoLine(line) {
return line.every((el) => !el);
}
class BingoCard {
constructor() {
// 1 ~ 75を持つ配列
this.list = new Array(75).fill(null).map((_, i) => i + 1);
// カードを生成する
this.card = this.createCard();
}
// ここで5×5のマスのカードを生成する
createCard() {
this.card = Array.from(new Array(5), () =>
new Array(5).fill(0).map(() => {
const index = Math.floor(Math.random() * this.list.length);
const bingo = this.list[index];
this.list.splice(index, 1);
return bingo;
})
);
// 初期状態で真ん中のマスはfalse
this.card[2][2] = false;
return this.card;
}
// 引数でlotteryNumber(抽選された整数)を受け取り、カード内に同じ整数があるかをチェックする
// もしあれば該当箇所をfalseに書き換える
checkNumber(lotteryNumber) {
for (let i of this.card) {
const judgeNumber = i.includes(lotteryNumber);
if (judgeNumber) {
const changeNumber = i.indexOf(lotteryNumber);
i[changeNumber] = false;
}
}
return this.card;
}
// ビンゴがあるかをチェックする
checkBingo() {
const horizontalBingoResult = this.horizontalResult; // 縦
const verticalBingoResult = this.verticalResult; //横
const crossLineBingoResult = this.crossLineResult; //斜め
// いずれかがtrueであればビンゴ
return (
!!horizontalBingoResult.length ||
!!verticalBingoResult.length ||
!!crossLineBingoResult.length
);
}
// 横の列にビンゴがあるかをチェック
get horizontalResult() {
const result = [];
for (let i = 0, l = this.card.length; i < l; i++) {
const row = this.card[i];
if (isBIngoLine(row)) {
result.push(i);
}
}
return result;
}
// 縦の列にビンゴがあるかをチェック
get verticalResult() {
const result = [];
for (let i = 0, l = this.card.length; i < l; i++) {
const col = [...new Array(5)].map((_, key) => {
return this.card[key][i];
});
if (isBIngoLine(col)) {
result.push(i);
}
}
return result;
}
// 斜めの列にビンゴがあるかをチェック
get crossLineResult() {
const result = [];
const crossLineArr = [[], []];
[...new Array(this.card.length)].forEach((_, index) => {
crossLineArr[0].push([index, index]);
crossLineArr[1].push([index, this.card.length - index - 1]);
});
for (let i = 0, l = crossLineArr.length; i < l; i++) {
const line = crossLineArr[i].map((el) => {
return this.card[el[0]][el[1]];
});
if (isBIngoLine(line)) {
result.push(i);
}
}
return result;
}
}
ビンゴマネージャーで各処理を実行していく
ビンゴカードとビンゴマシーンのクラスを定義できたら、処理の内容を整理して実行していきます。
ビンゴマネージャーの責務
- ビンゴカードを10枚生成する
- ランダムな数字を抽選する
- 抽選した数字があれば穴を開ける
- ビンゴがあるかを判定する
- ビンゴカードが10枚中3枚ビンゴになったらゲームを終了する
function BingoManager() {
const bingoMachine = new BingoMachine();
// ビンゴカードを10枚生成する
const cardArr = [];
for (let i = 0, l = 10; i < l; i++) {
cardArr.push(new BingoCard());
}
// ビンゴカードがいくつあるのか判定する
function checkEnd() {
let num = 0;
cardArr.forEach((card, i) => {
num += card.checkBingo() ? 1 : 0;
if (card.checkBingo()) {
console.log(card.card, i);
}
});
return num;
}
// ビンゴになったカードが3枚以下の場合にゲームが続く
while (checkEnd() <= 2) {
// ランダムな数字を抽選する
const lotteryNumber = bingoMachine.drawBingo();
// ランダムな整数を抽選後に10枚のカードをチェックする
for (let i = 0, l = cardArr.length; i < l; i++) {
if (cardArr[i]) {
// 抽選した数字があれば穴を開ける
cardArr[i].checkNumber(lotteryNumber);
}
}
}
console.log(cardArr);
}
// 関数を実行する
BingoManager();
完成時のコード
class BingoMachine {
constructor() {
// 1 ~ 75を持った配列
this.list = new Array(75).fill(null).map((_, i) => i + 1);
}
//毎回ランダムな整数を生成し、生成された値をlistから無くす
drawBingo() {
const index = Math.floor(Math.random() * this.list.length);
const bingo = this.list[index];
this.list.splice(index, 1);
return bingo;
}
}
// 配列の中身が全てfalseなのかをチェックします。
function isBIngoLine(line) {
return line.every((el) => !el);
}
class BingoCard {
constructor() {
// 1 ~ 75を持つ配列
this.list = new Array(75).fill(null).map((_, i) => i + 1);
// カードを生成する
this.card = this.createCard();
}
// ここで5×5のマスのカードを生成する
createCard() {
this.card = Array.from(new Array(5), () =>
new Array(5).fill(0).map(() => {
const index = Math.floor(Math.random() * this.list.length);
const bingo = this.list[index];
this.list.splice(index, 1);
return bingo;
})
);
// 初期状態で真ん中のマスはfalse
this.card[2][2] = false;
return this.card;
}
// 引数でlotteryNumber(抽選された整数)を受け取り、カード内に同じ整数があるかをチェックする
// もしあれば該当箇所をfalseに書き換える
checkNumber(lotteryNumber) {
for (let i of this.card) {
const judgeNumber = i.includes(lotteryNumber);
if (judgeNumber) {
const changeNumber = i.indexOf(lotteryNumber);
i[changeNumber] = false;
}
}
return this.card;
}
// ビンゴがあるかをチェックする
checkBingo() {
const horizontalBingoResult = this.horizontalResult; // 縦
const verticalBingoResult = this.verticalResult; //横
const crossLineBingoResult = this.crossLineResult; //斜め
// いずれかがtrueであればビンゴ
return (
!!horizontalBingoResult.length ||
!!verticalBingoResult.length ||
!!crossLineBingoResult.length
);
}
// 横の列にビンゴがあるかをチェック
get horizontalResult() {
const result = [];
for (let i = 0, l = this.card.length; i < l; i++) {
const row = this.card[i];
if (isBIngoLine(row)) {
result.push(i);
}
}
return result;
}
// 縦の列にビンゴがあるかをチェック
get verticalResult() {
const result = [];
for (let i = 0, l = this.card.length; i < l; i++) {
const col = [...new Array(5)].map((_, key) => {
return this.card[key][i];
});
if (isBIngoLine(col)) {
result.push(i);
}
}
return result;
}
// 斜めの列にビンゴがあるかをチェック
get crossLineResult() {
const result = [];
const crossLineArr = [[], []];
[...new Array(this.card.length)].forEach((_, index) => {
crossLineArr[0].push([index, index]);
crossLineArr[1].push([index, this.card.length - index - 1]);
});
for (let i = 0, l = crossLineArr.length; i < l; i++) {
const line = crossLineArr[i].map((el) => {
return this.card[el[0]][el[1]];
});
if (isBIngoLine(line)) {
result.push(i);
}
}
return result;
}
}
function BingoManager() {
const bingoMachine = new BingoMachine();
// ビンゴカードを10枚生成する
const cardArr = [];
for (let i = 0, l = 10; i < l; i++) {
cardArr.push(new BingoCard());
}
// ビンゴカードがいくつあるのか判定する
function checkEnd() {
let num = 0;
cardArr.forEach((card, i) => {
num += card.checkBingo() ? 1 : 0;
if (card.checkBingo()) {
console.log(card.card, i);
}
});
return num;
}
// ビンゴになったカードが3枚以下の場合にゲームが続く
while (checkEnd() <= 2) {
// ランダムな数字を抽選する
const lotteryNumber = bingoMachine.drawBingo();
// ランダムな整数を抽選後に10枚のカードをチェックする
for (let i = 0, l = cardArr.length; i < l; i++) {
if (cardArr[i]) {
// 抽選した数字があれば穴を開ける
cardArr[i].checkNumber(lotteryNumber);
}
}
}
console.log(cardArr);
}
// 関数を実行する
BingoManager();
まとめ
今回はJavaScriptのクラスを使ってビンゴゲームを作ってみました!
クラスを使用することでビンゴカード10枚を生成し、管理することが簡単に行うことができ、可読性の良い実装ができました!
これまでクラスを使用する機会がほとんどありませんでしたが、クラス内でデータと処理をまとめることで、オブジェクトを安全で簡単に扱うことができるので、今後も使用していきたいと思いました。
JavaScriptのお仕事に関するご相談
Bageleeの運営会社、palanではJavaScriptに関するお仕事のご相談を無料で承っております。
zoomなどのオンラインミーティング、お電話、貴社への訪問、いずれも可能です。
ぜひお気軽にご相談ください。
この記事は
参考になりましたか?
0
0
関連記事
2018年7月6日
【js】jQueryでできるハンバーガーメニューの作成
2018年6月18日
プログレスバーを簡単に実装できるprogressbar.js
2018年5月8日
画像に簡単にアニメーションをつけるcurtain.js
2018年2月14日
【js】jQueryでできるアコーディオンメニューの作成
2017年9月4日
【JS】スクロールした時にCSSanimationを発動させる「scrollMonitor」
簡単に自分で作れるWebAR
「palanAR」はオンラインで簡単に作れるWebAR作成ツールです。WebARとはアプリを使用せずに、Webサイト上でARを体験できる新しい技術です。
palanARへpalanでは一緒に働く仲間を募集しています
正社員や業務委託、アルバイトやインターンなど雇用形態にこだわらず、
ベテランの方から業界未経験の方まで様々なかたのお力をお借りしたいと考えております。
運営メンバー
Eishi Saito 総務
SIerやスタートアップ、フリーランスを経て2016年11月にpalan(旧eishis)を設立。 マーケター・ディレクター・エンジニアなど何でも屋。 COBOLからReactまで色んなことやります。
sasakki デザイナー
アメリカの大学を卒業後、日本、シンガポールでデザイナーとして活動。
やまかわたかし デザイナー
フロントエンドデザイナー。デザインからHTML / CSS、JSの実装を担当しています。最近はReactやReact Nativeをよく触っています。
Sayaka Osanai デザイナー
Sketchだいすきプロダクトデザイナー。シンプルだけどちょっとかわいいデザインが得意。 好きな食べものは生ハムとお寿司とカレーです。
はらた エンジニア
サーバーサイドエンジニア Ruby on Railsを使った開発を行なっています
こぼり ともろう エンジニア
サーバーサイドエンジニア。SIerを経て2019年7月に入社。日々学習しながらRuby on Railsを使った開発を行っています。
ささい エンジニア
フロントエンドエンジニア WebGLとReactが強みと言えるように頑張ってます。
Damien
WebAR/VRの企画・開発をやっています。森に住んでいます。
ゲスト bagelee
かっきー
まりな
suzuki
miyagi
ogawa
雑食デザイナー。UI/UXデザインやコーディング、時々フロントエンドやってます。最近はARも。
いわもと
デザイナーをしています。 好きな食べ物はラーメンです。
taishi kobari
フロントエンドの開発を主に担当してます。Blitz.js好きです。
kubota shogo
サーバーサイドエンジニア。Ruby on Railsを使った開発を行いつつ月500kmほど走っています!
nishi tomoya
aihara
グラフィックデザイナーから、フロントエンドエンジニアになりました。最近はWebAR/VRの開発や、Blender、Unityを触っています。モノづくりとワンコが好きです。
nagao
SIerを経てアプリのエンジニアに。xR業界に興味があり、unityを使って開発をしたりしています。
Kainuma
サーバーサイドエンジニア Ruby on Railsを使った開発を行なっています
sugimoto
asama
ando
iwasawa ayane
oshimo
異業界からやってきたデザイナー。 palanARのUIをメインに担当してます。 これからたくさん吸収していきます!