5日目:ランダムな値の設定と次のステージへの処理

5日目です。前回まではボタンには常に同じ数が表示されていました。HTMLのinput要素のvalueに直接数値を書いているからというのもあります。まあ、このようなゲームで同じ数字しか表示されないというのは非常に駄目なパターンです。まあ、通常ありえない状態になっていたということです。シンプルなゲームの場合、ランダムな処理にかなり依存することもあります。

ということで、今回はランダムにボタンの数値を設定する処理を作成してみます。単純に数値をランダムに設定するなら簡単です。が、TEN -10-の場合は、単純にランダムに生成した値を、そのままinput要素のvalue属性に設定するわけにはいきません。というのもTen-10-ではタッチ(クリック)した値の合計が10になる必要があるためです。つまり、24個のボタンが必ず消せるようになっていないといけません。
そこで、1〜9までの乱数を「var n = Math.floor(Math.random() * 9) + 1;」として生成します。得られた乱数値を配列に入れます。そして、10から乱数値を減算した結果も配列に追加して入れます。つまりnと10-nのペアを配列に入れていきます。
このまま、配列の内容をvalue属性に入れると、隣同士のボタンで合計が10になってしまいゲームとして面白くありません。そこで、配列の内容をシャッフルします。これは入れ替えるための位置を乱数を使って求めます。「var p1 = Math.floor(Math.random() * len);」「var p2 = Math.floor(Math.random() * len);」として2ヶ所の位置を求めます。あとは、この2ヶ所の内容を読み出して入れ替えます。これを数回繰り返せば配列内容がシャッフルされます。

あとはシャッフルされた配列の値をinput要素のvalue属性に設定すれば完了です。このような処理を関数setRandomValueにまとめておきます。これは、次に説明するステージクリアの処理に関連するためです。関数にしておかないと同じプログラムを2つ書くことになってしまいます。

次にステージをクリアした後の処理を変更します。前回までは同じ数値がinputボタンに表示されていたので面白くありませんでした。また、クリアしても次のステージが表示されることはありません。そこで、今回はクリアしたら再度ボタンを表示して値をランダムに割り当てて、再びゲームを続行できるようにします。
ステージをクリアしたらアラートダイアログを表示しますが、その後に処理を追加します。追加する処理はいくつかあります。まず、ボタンにランダムな値を割り当てることです。これは先ほど説明した処理を行うsetRandomValue関数を呼び出します。次に忘れてはいけないのが、input要素のスタイルを元に戻すことです。非表示を表示するようにし、背景色を透明にすることです。これをボタンの数だけ繰り返します。
あとは、画面に表示されているメッセージも消去しておきます。消去と言っても「document.getElementById("msg").innerHTML = "";」として空文字を設定することで文字が画面から消えるようになります。

ということで、ようやくステージクリア、ランダムな数値をボタンに設定できるようになってゲームっぽくなった感じ。だけど、かなりイマイチ・・・。ボタンが押しにくいというのもあって操作に難ありというところかも。次回は、そこらへんも改良したいところです。

[サンプルを実行する]

[サンプルをダウンロード]

HTMLファイルの内容

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>TEN</title>
</head>
<body>
<h1>TEN</h1>
<div>SCORE : <span id="score">0</span></div>
<form>
<!-- 1段目 -->
<input type="button" value="6">
<input type="button" value="7">
<input type="button" value="1">
<input type="button" value="6">
<br>
<!-- 2段目 -->
<input type="button" value="9">
<input type="button" value="3">
<input type="button" value="8">
<input type="button" value="2">
<br>
<!-- 3段目 -->
<input type="button" value="5">
<input type="button" value="7">
<input type="button" value="2">
<input type="button" value="6">
<br>
<!-- 4段目 -->
<input type="button" value="4">
<input type="button" value="4">
<input type="button" value="6">
<input type="button" value="8">
<br>
<!-- 5段目 -->
<input type="button" value="3">
<input type="button" value="4">
<input type="button" value="7">
<input type="button" value="2">
<br>
<!-- 6段目 -->
<input type="button" value="4">
<input type="button" value="5">
<input type="button" value="3">
<input type="button" value="8">
</form>
<div id="msg"></div>
<script src="main.js"></script>
</body>
</html>

JavaScriptファイル (main.js) の内容

// TEN HTML5 version
// (c) 2014 Cybermuse
// Arranger 古籏一浩
var score = 0;			// スコア(得点)を入れる変数
var count = 0;		// ボタンの合計を入れる変数
var prevNumber = 0;	// 直前にクリックした数字を入れる変数
var prevEle = null;		// 直前にクリックした要素を入れる変数
// 初期化処理
function init(){
	var ele = document.querySelectorAll("input");	// クリックしたら処理するようにイベントを設定
	for(var i=0; i<ele.length; i++){	// 要素の数だけ繰り返す
		ele[i].onclick = addNumber;	// クリック時に呼び出す関数を指定する
	}
	count = ele.length;	// input要素の総数を入れる
	setRandomValue(ele);	// input要素の数を渡す
}
// ランダムに値を設定する関数
function setRandomValue(ele){
	var len = ele.length;	// input要素の総数
	// input要素にランダムな値を設定する
	var num = [ ];
	for(var i=0; i<len; i+=2){	// 要素の数だけ繰り返す
		var n = Math.floor(Math.random() * 9) + 1;	// 1〜9までの数値をランダムに生成する
		num.push(n);
		num.push(10 - n);
	}
	// 配列要素をele.length回シャッフルする
	for(var i=0; i<len; i++){
		var p1 = Math.floor(Math.random() * len);	// input要素の数の範囲で乱数を発生させる
		var p2 = Math.floor(Math.random() * len);	// input要素の数の範囲で乱数を発生させる
		var n = num[p1];	// 2つの要素の内容を入れ替える
		num[p1] = num[p2];
		num[p2] = n;
	}
	// input要素に値を設定する
	for(var i=0; i<len; i++){	// 要素の数だけ繰り返す
		ele[i].value = num[i];	// 値を設定する
	}
}
// 2つの数字の合計が10かどうか調べる
function addNumber(){
	// 1個目のクリックの場合
	if (prevNumber === 0){
		prevEle = this;	// 要素の情報を変数に入れる
		prevEle.style.backgroundColor = "red";	// 背景を赤色にする
		prevNumber = parseInt(this.value);	// クリックされた要素の番号を変数に入れる
		return;	// 関数から抜ける
	}
	// 2個目のクリックの場合
	var total = prevNumber + parseInt(this.value);	// 直前の数値とクリックされた要素の数値を加算する
	if (total === 10){	// 合計が10の場合の処理
		this.style.visibility = "hidden";	// 現在の要素を非表示にする
		prevEle.style.visibility = "hidden";	// 前の要素を非表示にする
		prevNumber = 0;	// 数値を0にする
		document.getElementById("msg").innerHTML = "OK!";	// メッセージを表示する
		score = score + 1;	// スコア(得点)を追加する
		document.getElementById("score").innerHTML = score;	// スコア(得点)を表示する
		count = count - 2;	// 合計から2を引く
		if (count === 0){	// 全部消したかどうか調べる
			alert("ステージクリア!");
			var ele = document.querySelectorAll("input");	// input要素を取得する
			setRandomValue(ele);	// 乱数値を設定する
			for(var i=0; i<ele.length; i++){
				ele[i].style.visibility = "visible";	// 表示する
				ele[i].style.backgroundColor = "";	// 透明にする
			}
			count = ele.length;	// input要素の総数を入れる
			document.getElementById("msg").innerHTML = "";	// メッセージをクリア
		}
		return;	// 関数から抜ける
	}
	// 合計が10でなかった場合
	prevNumber = 0;	// 数値を0にする
	prevEle.style.backgroundColor = "";	// 透明にする
	document.getElementById("msg").innerHTML = "合計が10じゃないよ!";	// メッセージを表示する
}
init();	// 初期化処理を呼び出す