オブジェクト指向っぽくオセロを作る4

Viewオブジェクトの続きです。

少し発展

前回Viewオブジェクトのpaintメソッドが呼ばれるたびに、毎回全てのセルが削除されるという話をしました。しかし、全てのセルを描写しなおすのではなく、変更された箇所のみ描写しなおすほうが効率が良いでしょう。ここでは変更のあった箇所のみ描写しなおす処理を記述します。ちなみに以前の処理は効率が悪いだけであって、ゲームを進行する上では問題ありません。

var View = {
	/**
	 * Boardクラスから生成したboardオブジェクトをセットする
	 */
	setBoard : function(board){
		this._board = board;
	},
	/**
	 * boardの情報を実際に盤として描写するための処理
	 * 変更された箇所のみを再度描写しなおす
	 */
	paint : function() {
		/**
		 * 指定された種類のセルのDOM要素を作成する
		 * typeはblack, white, emptyのいずれか
		 * なお、この関数はpaintメソッド内でのみ有効
		 */
		var makeElement = function(type,id,x,y){
			var element;
			if(type != "black" && type != "white" && type != "empty"){
				throw new Error("illegal argument 'type': "+type);
			}else{
		    	element = document.getElementById(type).cloneNode(true);
				if(!element)
					throw new Error("idが"+type+"のDOM要素をクローンできませんでした。");				
			}
			element.style.left = 32 * x + "px";
			element.style.top = 32 * y + "px";
			element.id = id;
			return element;
		};
		if(!this._board)
			throw new Error("board is null/undefined. please call setBoard method before paint.");
		var board_element = document.getElementById("board");
		for ( var y = 0; y < 8; y++) {
		    for ( var x = 0; x < 8; x++) {
		    	/*
		    	 * boardオブジェクトが示す駒と
		    	 * DOM要素が示す盤の駒を比較
		    	 * 差異がある場合だけ描写を行う
		    	 */
		    	var nType; //boardオブジェクトの示す駒の種類
		    	switch ( this._board.getPiece(x, y) ) {
				case Piece.BLACK:
					nType="black";
					break;
				case Piece.WHITE:
					nType="white";
					break;
				case Piece.EMPTY:
					nType="empty";
					break;
				}
		    	//DOM要素の示す駒を取ってくる
		    	var id = "cell" + (x + 1  + y * 8); //idはcell1からcell64まで
		    	var bElement = document.getElementById(id);
		    	if(bElement){ //一番最初はDOM要素がないのでエラーではない
		    		var bType = bElement.className; //classは駒の種類に対応している
		    	}
		    	//同じなら描写しなおす必要がないので次の周に
		    	if(nType && bType == nType)
		    		continue;
		    	else{ //違うなら
		    		if(bElement) //なおかつ現在DOM要素があるなら
		    			board_element.removeChild(bElement); //DOM要素を取り除く
		    	}		    		
		    	//新たに追加するDOM要素を作る
		    	var nElement = makeElement(nType, id, x, y);
		    	if(nElement){
		    		board_element.appendChild(nElement);
		    	}
		    }
		}
	}
};

paintメソッドをご覧ください。ここでは最初にmakeElementという関数を設けました。これは指定されたDOM要素を作成するための関数です。なお、この関数はpaintメソッドの内部でのみ有効となります。次に二重になっているfor文の内側をご覧ください。ここではまず、boardオブジェクトの示す駒の情報を取得しています。次にDOM要素が表す駒の情報を取得しています。前に各セルのidはcell1からcell64までのいずれかになるという話をしました。このidを元にして、セルのDOM要素を取得しています。そして次にセルのDOM要素がきちんと取得できたのか調べます。ただし一番最初、つまり何も描写されていない状態ではDOM要素は取得できません。そのため、DOM要素が取得できなくてもエラーではありません。次にDOM要素からclassを取得しています。classの値は駒の種類、つまりblack、white、emptyのいずれかに対応しています。
boardの示す駒の種類と、DOM要素の示す駒の種類が分かりました。ここでこの二つを比較します。そして差異がある場合だけ、古いDOM要素を削除した後、新しいDOM要素を作成して追加しています。

ここまでのまとめ

ここまでのソースコード一式を載せておきます。バグがあれば、報告していただけると嬉しいです。
oop-othello.zip 直

次回はいよいよゲームの流れを管理する「オセロのルール」に対応するOthelloオブジェクトを作っていきます。
Othelloオブジェクトを作ろうかと考えていたのですが、Viewオブジェクトに少し手を加えることにしました。