駒台を実装する ~sfen形式からの持ち駒配列への変換など~

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

sfen形式のデータを読み込ませ、持ち駒も含めて、駒台に表示するところまでの実装ができたので、そのロジックを記録しておく。

だんたんとプログラムが長くなってきているので、すべてを載せるのが冗長な感じになってきているが、とりあえずは、showCapture関数から紹介していく。

showCapture関数の実装

まずは、プログラムコードから。

var showCapture = function() {

  var black = document.getElementById("capture_black");
  while(black.firstChild) {
    black.removeChild(black.firstChild);
  }

  cb.sort(function (a,b){
    return b-a;	
  });

  for(var i = 0; i < cb.length; i++){
    var c = piece[cb[i]].cloneNode(true);
    c.style.left = (5+(i%5) * 60) + "px";
    c.style.top = (5+((i-i%5)/5) * 64) + "px";	
    black.appendChild(c);
  }

  var white = document.getElementById("capture_white");
  while(white.firstChild) {
    white.removeChild(black.firstChild);
  }

  cw.sort(function (a,b){
    return b-a;	
  });

  for(var i = 0; i < cw.length; i++){
    var c = piece[cw[i]].cloneNode(true);
    c.style.left = (5+(i%5) * 60) + "px";
    c.style.top = (165-((i-i%5)/5) * 64) + "px";
    white.appendChild(c);
  }

};

前回の記事で紹介した持ち駒配列のソート関数は、結局、このshowCapture関数の中に移動させた。駒台の上の駒の表示については、styleのleftプロパティとtopプロパティの値を操作しているだけで、showBoard関数の中での各升目への駒配置と基本的な考え方は変わらない。

クロージャにて、それぞれの駒にonclick時の挙動を定義する必要があるだろうが、まずは、表示することを目的とするため、それは次回以降での実装範囲としたい。

sfen形式の持ち駒処理

sfen形式の文字列をプログラムで扱えるような盤配列や持ち駒配列に変換するわけだが、ここのロジックは少々読みにくくなった。

var sfen2Board = function(_sfen) {

  var sfen2piece={
    P: FU,  L: KY , N: KE, S: GI, G: KI ,B: KA ,R: HI ,K: OU, 
    p: EFU, l: EKY, n: EKE,s: EGI,g: EKI,b: EKA,r: EHI,k: EOU
  };

  var sfen = _sfen;
  var plus = EMPTY;
  var capture_roop = 1;
  var b = [];

  for(var i = 0; i < 11; i++){
    b.push(OUT_OF_BOARD);
  }

  for(var i = 0; i < sfen.length; i++){
    if(b.length < 100){
      if(sfen.charAt(i) >= 1 && sfen.charAt(i) <= 9) {
        for(var j = 0; j < sfen.charAt(i); j++){
          b.push(EMPTY);
        }
      }else if(sfen.charAt(i)=="/"){
        b.push(OUT_OF_BOARD);
      }else if(sfen.charAt(i)=="+") {
        plus = PROMOTED;
      }else{
        b.push(sfen2piece[sfen.charAt(i)] + plus);
        plus = EMPTY;
      }

      if(b.length == 100){
        console.log(i);
        for(var j = 0; j < 11; j++){
          b.push(OUT_OF_BOARD);
        }
      }
    }else{

//if(sfen.charAt(i) == " " || sfen.charAt(i) == "w" || sfen.charAt(i) == "b" ) { 
//手番情報の読み込みは考えないと……

      if(sfen.charAt(i) == " " || sfen.charAt(i) == "w") {
        continue;
      }
      if(sfen.charAt(i) >= 1 && sfen.charAt(i) <= 9) {
        capture_roop = sfen.charAt(i);
      }else{
        for(var j = 0; j < capture_roop; j++){
          console.log(sfen.charAt(i));
          if(sfen2piece[sfen.charAt(i)]>ENEMY){
            cw.push(sfen2piece[sfen.charAt(i)]);
          }else{
            cb.push(sfen2piece[sfen.charAt(i)]);
          }
        }
        capture_roop = 1;
      }
    }
  }
//	console.log(b);
//	console.log(cb);
//	console.log(cw);
  return b;
};

実は、このロジックでは、手番を表す”b”(先手番の意味)と、後手の持ち駒である”b”(後手の角行)が区別できない。手番情報を保持するロジックを実装したときに、合わせて、修正する予定である。

sfenの持ち駒ゾーンにて、数字が現れた場合には、その後に続く”駒”の数を意味している。例えば、”4G5P”となっていると先手番の銀が4枚、歩が5枚の意味になる。その制御をしているのが”capture_roop変数”である。

しかし、とりあえず、正しく動くことだけを優先した結果、プログラムコードが読みにくく、美しくないものになってしまった。なにしろ、盤配列は関数内の変数”b”に格納し、returnさせる挙動にしているのに、持ち駒配列については、グローバルにいる”cb”と”cw”を直接触っているのが、まさにアンチパターンな感じだ。

ここは、どこかでリファクタリングしたい。

処理結果

このプログラムで処理した結果を記録しておきたい。

board = sfen2Board("lr6l/4k1g2/2+B2S1pp/ppp2Sp2/9/P1PpNPP2/1PGG4P/7R1/L1K5L w S4Pbgs3np 1");

渡したsfen文字列は上記の通り。

これを処理した結果、表示された盤面がこれ。

capture_05

……というわけで、持ち駒の駒台への表示が実装できたので、いよいよ駒の稼動域の判定や駒移動時の相手の駒を取る処理を考えていきたい。