15puzzleとは?

  • 空欄の上下左右にあるタイルをクリックするとそのタイルが移動してパズルを解くゲームです。
  • 1~15まで順番になるように並べるゲームです。

制作結果

(見た目は環境によって違うこともあります。)

ソースコード

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>15puzzle</title>
	<style type="text/css" media="screen">
		.tile {
			width: 70px;
			height: 70px;
			border: 1px solid blue;
			border-radius: 10px;
			text-align: center;
			font-size: 36px;
			background-color: white;
			box-shadow: rgb(128, 128, 128) 5px 5px;
		}	
	</style>
	<script>
		"use strict";

		//広域変数
		var tiles = [];

		//初期化関数
		function init () {
			var table = document.getElementById("table")

			for (var i=0; i < 4; i++) {
				var tr = document.createElement("tr")

				for (var j = 0; j< 4; j ++) {
					var td = document.createElement("td")

					var index = i*4 + j;
					td.className = "tile";
					td.index = index;
					td.value = index;
					td.textContent = index == 0? "":index;
					td.onclick = click;
					tr.appendChild(td);
					tiles.push(td);
				}
				table.appendChild(tr);
			}

			for(var i=0; i<1000; i++) {
				click({
					srcElement: {
						index: Math.floor(Math.random()*16)
					}
				})
			}

			function click(e) {
				var i = e.srcElement.index;

				if (i-4 >= 0 &amp;&amp; tiles[i-4].value == 0) {
					swap(i, i-4);
				} else if (i+4 < 16 &amp;&amp; tiles[i+4].value == 0) {
					swap(i, i+4)
				} else if (i%4 != 0 &amp;&amp; tiles[i-1].value == 0) {
					swap(i, i-1)
				} else if (i%4 != 3 &amp;&amp; tiles[i+1].value == 0) {
					swap(i, i+1)
				}
			}

			function swap(i,j) {
				var tmp = tiles[i].value;

				tiles[i].textContent = tiles[j].textContent;
				tiles[i].value = tiles[j].value;
				tiles[j].textContent = tmp;
				tiles[j].value = tmp;
			}
		}
	</script>
</head>
<body onload="init()">
	<table id="table"></table>
</body>
</html>

ソースコード解説

  • 19列 – “use strict”を記述しておくと、より厳密にエラーチェックが行われます。潜在的なバグを軽減させるためにも記述しておくことをお勧めします。
  • 25列-init()では初期化をおこなっています。
  • 26列-table要素への参照を取得しています。
  • 28列~29列- for文を4回繰り返すことで4行のテーブルを作成しています。
  • 31列~32列- for文を4回繰り返すことで列を四つ作成しています。
  • 40列- (31列~32列)で作成した列を(28列~29列)で作成した行に挿入しています。要は4X4の盤面をJavaScriptから作成しているだけです。

value=0のタイルは何も描画しない空のタイルです。今回のポイントはindexとvalueプロパティの追加方です。

indexはタイルの並び順で、valueはタイルに描画されている数値です。このふたつを混乱しないように注意しましょう。

以下はテーブルの例となります。

index=0
value=3
表示数値=3
index=1
value=10
表示数値=10
index=2
value=7
表示数値=7
index=3
value=1
表示数値=1
index=4
value=6
表示数値=6
index=5
value=11
表示数値=11
index=6
value=2
表示数値=2
index=7
value=0
表示数値=空
index=8
value=8
表示数値=8
index=9
value=9
表示数値=9
index=10
value=14
表示数値=14
index=11
value=13
表示数値=13
index=12
value=12
表示数値=12
index=13
value=4
表示数値=4
index=14
value=15
表示数値=15
index=15
value=5
表示数値=5
  • 54列- タイルがクリックされるとクリックされるとclick(e)が呼び出されます。そのタイルの上下左右のどこかに空タイル(valueプロパティが0のタイル)があった場合、それらタイルのvalueを入れ替えます。そのためには、クリックされたタイルの上下左右に空タイルがあるか調べる必要があります。
  • 55列-クリックしたタイルのindexを取得します。よって上のタイルはindex-4下のタイルはindex+4左のタイルはindex-1右のタイルはindex+1で求められます。

ただし、値を比較する際には若干の注意が必要です。例えば最上段がクリックされた場合、その上に行はないので比較できません。逆に最下段がクリックされた場合、その下に行はありません。

  • 57列~65列-これらの処理をすべてclick(e)の中で行われています。

例えば、上のタイルとの比較は以下のように行っています。

if(i-4 >= 0 &amp;&amp; tiles[i-4].value == 0) {
swap(i, i-4)
}

index-4が0以下であるかを最初にチェックし、それがtrueの場合、すなわち上にタイルが存在する場合に限り、「tiles[i-4].value」の値が0か比較を行っています。

4つのif文は上下左右の比較を行っているので見比べてみるとその意図がわかると思います。条件式が成立した場合「swap(i,j)」を呼び出してタイルの番号を入れ替えています。

textContent(画面表示用)とvalue(内部管理用)のプロパティを入れ替えていることに注意してください。

  • 46列~52-列ちなみに、こちらの列でタイルが1000回クリックされた状況を再現しています。

Webゲーム開発

プログラミングメイン