Countermove(応手)とは何ですか?

いま、待ち合わせのため時間が30分ほどあるので記事2つほど書く。

Qhapaqさんが技術書典4で『科学するコンピュータ将棋』という同人誌を販売された。

この校正のお手伝いをしているときに、Countermoveの説明が丸ごと間違っていることに気づいたので、それを以下のようにメールで指摘した。Countermoveについて説明する記事として、わかりやすいと思うので、その全文をここに引用する。

Countermove(1手前の相手の指し手に対する指し手=応手)、follow up move(2,4手前の自分の指し手に対する指し手=継続手)は、Stockfish 7(?)で導入され、長い持ち時間で非常に効果があったオーダリング手法であり、チェス・将棋以外のゲームAIにも応用が利く素晴らしいアイデアなのでここで紹介しておく。


https://chessprogramming.wikispaces.com/Countermove+Heuristic
の疑似コードを見ると良いと思います。
> if ( isNonCapture (move) )
> counterMove[previousMove.from][previousMove.to] = move;

捕獲する指し手でなければ(捕獲する指し手が良いのは当たり前だから)、直前の指し手に対する
応手として現在の指し手を登録するということです。

そして、オーダリングのときに、直前の指し手が一致した場合、すなわち
> if ( movelist[i].move == counterMove[previousMove.from][previousMove.to] )
> movelist[i].score += counterMoveBonus;

である場合、このオーダリングのためのスコアにボーナスを加点します。

なので、コンセプトとしては、
・指し手Xに対する応手として指し手Yがベストであったなら、他の兄弟局面でも指し手Xが出てきたときは、指し手Y
を早い段階で試そうね
ということですね。

このへんを踏まえると、

> Countermoveとは良い返しの手のストックのようなもので、評価値の高い手(より具

説明例を以下に書きましたので適当にコピペして使ってもらって良いです。(`・ω・´)b

////

Countermoveとは、ある指し手に対する応手のことです。
ある局面において指し手Xが指されたときに、応手として指し手Yがベストであるとわかれば、他の局面でも指し手Xが指されたときには、指し手Yがベストである可能性は高く、指し手Yの変化を早い段階で調べるのが良いでしょう。

そのために、指し手Xに対する指し手Yをペアにして記憶しておき、オーダリングのときに、直前の指し手が指し手Xであるなら、指し手Yに対してボーナスを加点して、早い段階でその変化を調べるように仕向けます。これがCountermoveの考えかたです。

このアイデアを実現する疑似コードとしては以下のようになります。

■ counterMove配列の更新

まず、その局面でのベストの指し手を更新した時に以下のようにcounterMove配列を更新します。

isNonCapture()は捕獲する指し手かどうかを判定する関数で、捕獲する指し手が良い指し手であるのは当然なので、このときはcounterMove配列は更新しません。previousMove.fromは直前の指し手の移動元の升、previousMove.toは直前の指し手の移動先の升です。この疑似コードでは駒の種類は見ていません。

if ( score >= beta ) { // cutoff
if ( isNonCapture (move) )
counterMove[previousMove.from][previousMove.to] = move;

return score;
}

■ オーダリング時の処理

if ( movelist[i].move == counterMove[previousMove.from][previousMove.to] )
movelist[i].score += counterMoveBonus;

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です