将棋UI実装への道 ~駒クリック時のイベントを実装する~

この記事の所要時間は約 9 分 です。

前回記事において、将棋盤への駒配置までは実装できた。今回は、駒クリック時の挙動について、考えていきたい。

将棋UI実装への道 ~将棋盤の初期配置を実装する~
前回の記事で試したオセロの実装例を参考に将棋盤を作ってみたので、気になったところを述べてみる。 なお、駒と将棋盤の画像は、以下...

前回のshowBoard関数

前回、実装したshowBoard関数は、下記のような感じだった。

var showBoard = function() {
  var b = document.getElementById("board");
  while(b.firstChild) {
    b.removeChild(b.firstChild);
  }
  for(var y = 1; y <= 9; y++){
  for(var x = 1; x <= 9; x++){
    var c = piece[board[x][y]].cloneNode(true);
    c.style.left = (30+(x-1) * 60) + "px";
    c.style.top = (30+(y-1) * 64) + "px";    
    c.onclick = function(){
       console.log(x + ":" + y);
    };
    b.appendChild(c);
  }
  }
};

そして、これだと、どの駒をクリックしたときにも、コンソールには、「10:10」と表示される。これは、変数xと変数yのスコープの問題であるので、回避策を考える必要がある。

変数のスコープ問題の回避

このスコープ問題については、以下のように実装することで回避できる。(そもそも、元にしたオセロのコードでも、どうようの記述があったので、これを参考にすれば、もっと早く解決できていたはずだ)

var showBoard = function() {
  var b = document.getElementById("board");
  while(b.firstChild) {
    b.removeChild(b.firstChild);
  }
  for(var y = 1; y <= 9; y++){
  for(var x = 1; x <= 9; x++){
    var c = piece[board[x][y]].cloneNode(true);
    c.style.left = (30+(x-1) * 60) + "px";
    c.style.top = (30+(y-1) * 64) + "px";		
      (function(){
        var _x = x,_y = y;
        c.onclick = function(){
            console.log(_x + ":" + _y);
          };
      })();
    b.appendChild(c);
  }
  }
};

無名のfunctionで定義することで、変数”_x”と変数”_y”のスコープが定められており、これで、駒をクリックすると正しい升目の座標が返ってくるようになった。(このあたりの技術的な知識については、見よう見まねでやっているので、有識者の方がいたら、ぜひ、コメント欄にツッコミをいただきたい)

譜号の実装

ここまできたら、もう一歩進めてみたい。クリックした升目の棋譜と駒の種類をコンソールに表示するようにしてみたい。

コードとしては、以下のような感じだ。

var showBoard = function() {
  var b = document.getElementById("board");
  while(b.firstChild) {
    b.removeChild(b.firstChild);
  }
  for(var y = 1; y <= 9; y++){
  for(var x = 1; x <= 9; x++){
    var c = piece[board[x][y]].cloneNode(true);
    c.style.left = (30+(x-1) * 60) + "px";
    c.style.top = (30+(y-1) * 64) + "px";		
      (function(){
        var _x = x,_y = y;
        c.onclick = function(){
            console.log(kazu2suji[_x] + kazu2dan[_y] + kazu2koma[board[_x][_y]]);
            movePiece();
          };
      })();
    b.appendChild(c);
  }
  }
};

ちなみに、”movePiece”関数は、次回、実装する。ここでのポイントは、kazu2suji、kazu2dan、kazu2komaの役割だ。もうちょっと、命名のセンスで、なんとかならなかったのか、という気もするが、これらの配列では、将棋盤上の座標を棋譜の譜号に、駒を表す数値を駒の略称に変換する役割を担っている。

具体的には、以下のように実装している。

var kazu2koma={
  1:"歩", 2:"香", 3:"桂", 4:"銀", 5:"金", 6:"角", 7:"飛", 8:"王",
  9:"と",10:"杏",11:"圭",12:"全",13:"",14:"馬",15:"龍",16:"",
  17:"歩", 18:"香",19:"桂",20:"銀", 21:"金",22:"角", 23:"飛",24:"王",
  25:"と",26:"杏",27:"圭",28:"全",29:"",30:"馬",31:"龍",32:""
};

var kazu2suji={
  1:"9", 2:"8", 3:"7", 4:"6", 5:"5", 6:"4", 7:"3", 8:"2",	9:"1"
};

var kazu2dan={
  1:"一", 2:"二", 3:"三", 4:"四", 5:"五", 6:"六", 7:"七", 8:"八",	9:"九"
};

kazu2komaについては、もう少し工夫の余地はありそうだが、この配列を呼び出すことで、クリックした駒の譜号と駒の略称(歩、香、桂~馬、龍)が表示されるようになった。

Shogi-Board-console

上記がクリックした際のコンソールログだ。一見、うまく表示されてそうだ。

空の升目をクリックした時の問題

ところが、空の升目に配置された画像(ダミーなので、1pxの画像が配置されている)をクリックした時に、想定外のログが出た。

「1六undefined」のように出力されたわけだが、空の升目には、EMPTYという定数で数値のゼロが入っており、kazu2komaでゼロが定義されていなかったことによる。

この場合は、ゼロをEMPTYとして定義しなおすよりは、このconsole.logを呼ぶ際に、その升目に駒が配置されているかどうかをチェックするべきだろう。

具体的には、以下のような実装になると思う。

var showBoard = function() {
  var b = document.getElementById("board");
  while(b.firstChild) {
    b.removeChild(b.firstChild);
  }
  for(var y = 1; y <= 9; y++){
  for(var x = 1; x <= 9; x++){
    var c = piece[board[x][y]].cloneNode(true);
    c.style.left = (30+(x-1) * 60) + "px";
    c.style.top = (30+(y-1) * 64) + "px";		
      (function(){
        var _x = x,_y = y;
        c.onclick = function(){
          if(kazu2koma[board[_x][_y]] != EMPTY){
            console.log(kazu2suji[_x] + kazu2dan[_y] + kazu2koma[board[_x][_y]]);
            movePiece();
          };
        };
      })();
    b.appendChild(c);
  }
  }
};

これで、空の升目がクリックされた時には、処理が行われない。今は、コンソールへの譜号の表示しか実装していないため、この判定を入れる意味合いが薄いように感じるが、movePieceを実装した時には、このif文が意味を持ってくるはずだ。

次回への課題

次回は、ずばり、movePieceの実装である。

var movePiece = function() {
//	board[9][1] = EMPTY;
//	board[9][2] = EKY;
  showBoard();
};

board配列の中身を入れ替えてから、showBoardを呼ぶことで、駒の移動が実現できるはずだが、引数で座標を渡すなりした方がよさそうだ。このあたりは、次回、考える。