Bonanzaの駒の価値はどこに書かれているのか その1

Bonanzaで駒割を計算するときの、駒の価値はどこに書かれているのかというのは、簡単なようで少しトリッキーです。今回はこの問題について説明します。


まず、駒自体の価値は、param.hでdefineされています。

#define DPawn            87 /*  174 */
#define DLance          232 /*  464 */
#define DKnight         257 /*  514 */
#define DProPawn        534 /*  621 */
#define DProLance       489 /*  721 */
#define DSilver         369 /*  738 */
#define DProKnight      510 /*  767 */
#define DProSilver      495 /*  864 */
#define DGold           444 /*  888 */
#define DBishop         569 /* 1138 */
#define DRook           642 /* 1284 */
#define DHorse          827 /* 1396 */
#define DDragon         945 /* 1587 */
#define DKing         15000


param.hというファイル自体は、実は自動生成されるファイルで、棋譜からの学習時に、学習した駒の価値を書きだすコードが書かれています。(learn2.c)


ゆえに、param.hというファイルを直接編集したところで次回の学習のときに上書きされてしまいます。


さて、これらの値はどこで使われているかと言うと、ini関数(ini.c)で次のようにp_valueの初期化に使われています。

  p_value[15+pawn]       = DPawn;
  p_value[15+lance]      = DLance;
  p_value[15+knight]     = DKnight;
  p_value[15+silver]     = DSilver;
  p_value[15+gold]       = DGold;
  p_value[15+bishop]     = DBishop;
  p_value[15+rook]       = DRook;
  p_value[15+king]       = DKing;
  p_value[15+pro_pawn]   = DProPawn;
  p_value[15+pro_lance]  = DProLance;
  p_value[15+pro_knight] = DProKnight;
  p_value[15+pro_silver] = DProSilver;
  p_value[15+horse]      = DHorse;
  p_value[15+dragon]     = DDragon;

見ての通り、p_valueが駒の価値が入っている配列です。p_valueのpはpieceの頭文字で、valueは「値」ではなく、「価値」の意味でしょう。こうやって、変数名の意味を正しく理解するとソースの読解がしやすくなります。


さて、15というオフセット値が加算されているのは、Bonanzaでは駒をsigned(符号型)で表現するため、先手の駒は1〜15であり、後手の駒は-1〜-15という負の数になります。ゆえに、本来なら p_value [ abs(piece) ]と書くべきところですが、保木さんは、このabsにかかるコストが許せなかったのでしょう。ゆえに、absをせずとも、先手と後手の駒の価値を直接求められるように 15というオフセット値を加算するようにしてあるわけです。


ちなみに、後手の駒に対するp_valueの値も符号はマイナスではなく、プラスです。
このことは、set_derivative_param関数(ini.c)を見ればわかります。

  p_value[15-pawn]          = p_value[15+pawn];
  p_value[15-lance]         = p_value[15+lance];
  p_value[15-knight]        = p_value[15+knight];
  p_value[15-silver]        = p_value[15+silver];
  p_value[15-gold]          = p_value[15+gold];
  p_value[15-bishop]        = p_value[15+bishop];
  p_value[15-rook]          = p_value[15+rook];
  p_value[15-king]          = p_value[15+king];
  p_value[15-pro_pawn]      = p_value[15+pro_pawn];
  p_value[15-pro_lance]     = p_value[15+pro_lance];
  p_value[15-pro_knight]    = p_value[15+pro_knight];
  p_value[15-pro_silver]    = p_value[15+pro_silver];
  p_value[15-horse]         = p_value[15+horse];
  p_value[15-dragon]        = p_value[15+dragon];

一見すると、(pawnの値は1ですから) p_value[15]の値がセットされていないかのように見えますが、int関数で最初に次のようにゼロ初期化されているので心配ありません。

  for ( i = 0; i < 31; i++ ) { p_value[i]       = 0; }


つづく