56将棋開発ブログ

5×6マスのミニ将棋、「56将棋」で遊べるものをいろいろ開発してます。

Bonanza ver 6.0 のsearchr()とb_gen_checks()について

気圧が下がってプログラミングのやる気がでないので、ブログ更新してみます。(ひどい理由)

以前から気になっていたのですが、Bonanzaのコードに不可解な部分があるので書いておきます。

まず、searchr.cのsearchr関数の、historyの値によって非PVノードの探索深さを調節する部分なのですが、

//Bonanza ver 6.0 searchr.c 620行目から
//searchr()

else {
        int depth_reduced = 0;
        new_depth = depth + extension;

        /* reductions */
        if ( 2*PLY_INC <= new_depth
             && ! ptree->nsuc_check[ply]
             && ! UToCap(MOVE_CURR)
             && ! ( I2IsPromote(MOVE_CURR)
                    && I2PieceMove(MOVE_CURR) != silver ) )
          {
            unsigned int key     = phash( MOVE_CURR, turn );
            unsigned int good    = ptree->hist_good[key]  + 1;
            unsigned int triedx8 = ( ptree->hist_tried[key] + 2 ) * 8U;

            if      ( good *160U < triedx8 ) { depth_reduced = PLY_INC * 3/2; }
            else if ( good * 50U < triedx8 ) { depth_reduced = PLY_INC * 2/2; }
            else if ( good * 19U < triedx8 ) { depth_reduced = PLY_INC * 1/2; }

            depth_reduced = PLY_INC;  /* ????????? */
            new_depth    -= depth_reduced;
          }
//以下略
}

となっていて、?マークのコメントを入れた行の処理で、直前の条件分岐が無意味になっているようにみえます。
(探索深さがhistoryの値に関係なく、同じになってしまうはず)


あとは、genchk.cのb_gen_checks関数に、持ち駒の飛車を打って王手する手を生成する処理があるのですが、
ここでは3手詰みルーチンの中合い問題でつかうために、玉との距離によって指し手にフラグを付加しています。
(MOVE_CHK_CLEARとMOVE_CHK_SET)

実際のコードはこうなっています。

//Bonanza ver 6.0 genchk.c 172行目から
//b_gen_checks() 


 if ( IsHandRook(HAND_B) )
    {
      unsigned int move;
      int file, dist, min_dist;
   
     //敵玉が盤の右端か左端にいるならmin_dist = 2,そうでないなら3
      if ( (int)aifile[sq_wk] == file1
	   || (int)aifile[sq_wk] == file9 ) { min_dist = 2; }
      else                                  { min_dist = 3; }
      
      //to += nfileなので、敵玉の↓方向への飛打
      for ( to = sq_wk+nfile, dist = 1; to < nsquare && BOARD[to] == empty;
	    to += nfile, dist += 1 )
	{
	  move = To2Move(to) | Drop2Move(rook);
	  if      ( dist == 1 )       { move |= MOVE_CHK_CLEAR; }
	  else if ( dist > min_dist ) { move |= MOVE_CHK_SET; }
	  *pmove++ = move;
	}

      //to -= 1なので、敵玉の←方向
      for ( file = (int)aifile[sq_wk]-1, to = sq_wk-1, dist = 1;
	    file >= file1 && BOARD[to] == empty;
	    file -= 1, to -= 1, dist += 1 )
	{
	  move = To2Move(to) | Drop2Move(rook);
	  if      ( dist == 1 ) { move |= MOVE_CHK_CLEAR; }
	  else if ( dist > min_dist ) { move |= MOVE_CHK_SET; }
	  *pmove++ = move;
	}
   
     //敵玉が盤の上端か下端にいるならmin_dist = 2,そうでないなら3
      if ( sq_wk < A8 || I2 < sq_wk ) { min_dist = 2; }
      else                            { min_dist = 3; }

      //to += 1なので、敵玉の→方向
      for ( file = (int)aifile[sq_wk]+1, to = sq_wk+1, dist = 1;
	    file <= file9 && BOARD[to] == empty;
	    file += 1, to += 1, dist += 1 )
	{
	  move = To2Move(to) | Drop2Move(rook);
	  if      ( dist == 1 )       { move |= MOVE_CHK_CLEAR; }
	  else if ( dist > min_dist ) { move |= MOVE_CHK_SET; }
	  *pmove++ = move;
	}
      
      //to -= nfileなので、敵玉の↑方向
      for ( to = sq_wk-nfile, dist = 1; to >= 0 && BOARD[to] == empty;
	    to -= nfile, dist += 1 )
	{
	  move = To2Move(to) | Drop2Move(rook);
	  if ( (int)airank[to] == rank3 ) { move |= MOVE_CHK_CLEAR; }
	  if      ( dist == 1 )           { move |= MOVE_CHK_CLEAR; }
	  else if ( dist > min_dist )     { move |= MOVE_CHK_SET; }
	  *pmove++ = move;
	}
    }

玉が端にいるかどうかで、どの距離まで中合いを考えるかが違ってくるようなのですが、
コメントを付加したループの順番がおかしいようにみえます。

正しくは、

敵玉が盤の右端か左端にいるならmin_dist = 2,そうでないなら3
↑方向のループ
↓方向のループ

敵玉が盤の上端か下端にいるならmin_dist = 2,そうでないなら3
→方向のループ
←方向のループ

という順番であり、実際に後手番用のw_gen_checks()ではそうなっています。


以前にBonanzaのページに載っているメールアドレスにご連絡したことがあるのですが、
お忙しいようでお返事をいただけませんでした。

開発者の保木邦仁様の連絡先も知らないですし、ブログに書くことにしました。

コンピュータ将棋関係者の方がみていらっしゃるなら、なにかコメントしていただければと思います。

それでは。