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〜 を用いて比較してある。