sfen形式での盤面データ設定への対応

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

将棋UI実装への道」と題して、JavaScriptによる将棋プログラミングを楽しんできたが、今回のテーマは、厳密には、UI(ユーザーインターフェース)ではない。

今回、コーディングするのは、sfen形式という形式での盤面データのやり取りに対応するためのロジックだ。

sfen形式とは?

sfen形式の説明については、他に詳しいサイトがあるので、詳細については、そちらに譲る。

ここで、概要だけ説明すると、将棋GUIソフトと思考エンジンの通信を目的として、Tord Romstad氏が考案したUSI(Universal Shogi Interface)というプロトコルにおけるデータ保持形式で、Shogi Forsyth-Edwards Notationの略であるという。

何らかの方法で盤面情報を保持する必要があるのであれば、このsfen形式に対応しておくことで、100桁に満たない文字列の中で盤面を表現することができるようになるし、副次的な効果として、他のソフトとの互換性も担保できる。

今回は、この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 = "lnsgkgsnl/1r5b1/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL";
  var plus = EMPTY;
  var b = [];

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

  for(var i = 0; i < sfen.length; i++){
    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;
    }
  }

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

sfen2pieceで定義されているのが、sfen形式から駒定数への変換部分だ。

sfen文字列内に”数字”があれば、駒が置かれていない升目がその数ある、ということなので、その数の分だけEMPTYを入れる。

sfen文字列内に”/”がある場合には、それは、その段が終わったことを表すため、盤外であることを表す”OUT_OF_BOARD”を入れる。

sfen文字列内に”+”があった場合には、成り駒の表現であるため、これにも対応した。

これらの処理をした結果を盤情報の一次元配列として戻す。

sfen2Boardを呼び出す

ロードされた際に初期盤面を設定していたロジックをこのsfen2Boardを利用したロジックに変更してみる。

以下のような感じだ。

//	for(var i = 0; i <= 110 ; i++) {
//		board[i]=EMPTY;
//	}
//	board[19] = EKY;
//	board[18] = EKE;
//	board[17] = EGI;
//	board[16] = EKI;
//	board[15] = EOU;
//	board[14] = EKI;
//	board[13] = EGI;
//	board[12] = EKE;
//	board[11] = EKY;
//
//	board[22] = EHI;
//	board[28] = EKA;
//
//	board[31] = EFU;
//	board[32] = EFU;
//	board[33] = EFU;
//	board[34] = EFU;
//	board[35] = EFU;
//	board[36] = EFU;
//	board[37] = EFU;
//	board[38] = EFU;
//	board[39] = EFU;
//	
//	board[99] = KY;
//	board[98] = KE;
//	board[97] = GI;
//	board[96] = KI;
//	board[95] = OU;
//	board[94] = KI;
//	board[93] = GI;
//	board[92] = KE;
//	board[91] = KY;
//
//	board[82] = KA;
//	board[88] = HI;
//	
//	board[71] = FU;
//	board[72] = FU;
//	board[73] = FU;
//	board[74] = FU;
//	board[75] = FU;
//	board[76] = FU;
//	board[77] = FU;
//	board[78] = FU;
//	board[79] = FU;
//
  board = sfen2Board();
  showBoard();
};

元のロジックをコメントアウトしてみたが、ずいぶんとすっきりとした印象だ。sfen2board_1

無事に表示された達成感があるが、しかし、画像で見ると、以前のものとの差がわからない。

成り駒が表示されていることを確認するために、敵の「歩」をすべて、「と金」に変えてみよう。

この時のsfen文字列は、以下のような感じになる。

lnsgkgsnl/1r5b1/+p+p+p+p+p+p+p+p+p/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL

これで動かしてみる。

sfen2board_2

盤面情報に反映された。sfen形式からの盤面情報への変換についても、大枠のところは実装できたようだ。

持ち駒の問題

実は、上記のロジックでは、持ち駒の部分については、実装できていない。sfen形式は盤面情報を保持するため、当然、持ち駒についての表記方法はあるのだが、今のロジックは、この部分が未実装だ。

というのも、駒台の表現について、この将棋盤プログラムでどのように実装するかを決め切れていないため、そこに手をつけられないからだ。

この部分は次回への課題としたい。