Bonanzaの手駒のbit layoutはどうなっているか

■ Bonanzaの手駒のbit layoutはどうなっているか


Bonanzaで手駒がどう表現されているかはあまり知られていない。今回は、これについて詳しく調べておく。


手駒は、shogi.hで定義されている、局面を表わすposi_tというstructのなかに

  // 手駒
  unsigned int hand_black, hand_white;

というメンバがある。これが手駒である。すなわち、先手(black)、後手(white)の手駒それぞれをuint型(32bit無符号整数型)で保持している。


このbit layoutは次のようになっている。これはshogi.hにコメントがある。

  xxxxxxxx xxxxxxxx xxx11111  pawn   歩
  xxxxxxxx xxxxxxxx 111xxxxx  lance 香
  xxxxxxxx xxxxx111 xxxxxxxx  knight 桂
  xxxxxxxx xx111xxx xxxxxxxx  silver 銀
  xxxxxxx1 11xxxxxx xxxxxxxx  gold  金
  xxxxx11x xxxxxxxx xxxxxxxx  bishop 角
  xxx11xxx xxxxxxxx xxxxxxxx  rook  飛

歩であれば、下位5bitがその枚数を表わすということである。例えば、歩の枚数を取り出すI2HandPawnというマクロならば、shogi.hで次のように定義されている。

// 手駒に XXが何枚あるか。
// Isのほうはあるかないか。I2 は、枚数を返す。
#define I2HandPawn(hand)       (((hand) >>  0) & 0x1f)
#define I2HandLance(hand)      (((hand) >>  5) & 0x07)
…
#define IsHandPawn(hand)       ((hand) & 0x000001f)
#define IsHandLance(hand)      ((hand) & 0x00000e0)
…
#define IsHandRook(hand)       ((hand) & 0x0180000)


I2Hand〜というマクロはその駒の枚数を取り出す。


IsHand〜というマクロのほうは、その駒を持っているかだけを判定するためのもの(その駒を持っていれば非0が返る)なので、ビットシフトはする必要がない。


また、HAND_Bというマクロはblack(先手)の手駒。HAND_Wはwhite(後手)の手駒を表現する。これはshogi.hで次のように定義されている。

// 手駒
#define HAND_B              (ptree->posi.hand_black)
#define HAND_W              (ptree->posi.hand_white)


ptreeは現在探索中の探索木を表現するtree型の変数である。


ソース上は、HAND_B,I2HandPawnのようなマクロが多用されており、hand_black、hand_whiteという変数名が直接コード上に出てくる箇所はほとんど無い。


例えば次のように使われている。

  list0[ 0] = f_hand_pawn   + I2HandPawn(HAND_B);


■ まとめ


今回はBonanzaの手駒表現とそれに関連するマクロについて調べた。


持ち駒は、駒種ごとに配列に枚数を保持しているのではなく、uint型にpackして保持していた。


しかし、このようにするなら、持駒の優劣関係判定を次の手法で簡素化するために、隣のbit fieldとは1bitずつpaddingしておいたほうが良いと思う。


持駒の優劣関係判定 (1)
http://ameblo.jp/professionalhearts/entry-10003645855.html


持駒の優劣関係判定 (2)
http://ameblo.jp/professionalhearts/entry-10003663090.html


このようにpaddingしてあれば、utility.cのis_hand_eq_supe(手駒の優劣関係を判定する)で次のように書いてある部分は、簡素化できる。

  if ( IsHandKnight(u) < IsHandKnight(uref)
       || IsHandSilver(u) < IsHandSilver(uref)
       || IsHandGold(u)   < IsHandGold(uref)
       || IsHandBishop(u) < IsHandBishop(uref)
       || IsHandRook(u)   < IsHandRook(uref) ) { return 0; }

さきほど見たように、IsHand〜のほうは、その駒を持っているか持っていないかを判定するためのものだが、例えば、先手と後手との桂の枚数を比較するのであれば、I2HandKnightを用いるのは、ビットシフトが発生するので損である。


そこで、先手と後手との特定の種類の手駒の枚数を比較したいときは、上のようにIsHand〜 を用いて比較してある。