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のページに載っているメールアドレスにご連絡したことがあるのですが、
お忙しいようでお返事をいただけませんでした。
開発者の保木邦仁様の連絡先も知らないですし、ブログに書くことにしました。
コンピュータ将棋関係者の方がみていらっしゃるなら、なにかコメントしていただければと思います。
それでは。