手の並べ替え

手の並べ替えは、探索で候補手を調べる順番を工夫する技術である。 アルファベータ法は良い手から先に読むほど枝刈りが増えるため、 探索速度を大きく左右する。

概要

ミニマックス法では手順の順番は結果に影響しない。 しかしアルファベータ法では、 有望な手を先に調べるほど早く alphabeta の境界が更新され、 後続の枝を省きやすくなる。

そのため、現代的な将棋AIでは 「どの手を先に読むか」は探索アルゴリズムそのものと同じくらい重要である。

よく使われる順序

典型的には次のような順に試す。

  • 前回反復の Principal Variation 手
  • 置換表に入っている hash move
  • 良い駒取り
  • 昇格など価値の高い手
  • killer heuristic などの非捕獲手
  • その他の手

将棋では、

  • 王手
  • 駒取り
  • 成り
  • 受けの手

の扱いがチェスより少し複雑になるが、基本思想は同じである。

代表的な材料

Principal Variation 手

反復深化の前回反復で最善だった手は、次の反復でも有望であることが多い。

hash move

置換表に保存された最善手は、最も重要な順序情報のひとつである。

捕獲手の優先順位

駒取りについては、

のような方法で優先順位を付けることが多い。

非捕獲手の履歴

などが使われる。

実装例

単純化した例では、各手にスコアを付けて高い順に読む。

int scoreMove(const Move& move, const Position& pos) {
    if (move == hashMove(pos)) return 1000000;
    if (isWinningCapture(move, pos)) return 900000;
    if (isKiller(move)) return 800000;
    return historyScore(move);
}

void orderMoves(std::vector<Move>& moves, const Position& pos) {
    std::sort(moves.begin(), moves.end(),
        [&](const Move& a, const Move& b) {
            return scoreMove(a, pos) > scoreMove(b, pos);
        });
}

実際には全手を完全ソートせず、取り出し時に最大のものを選ぶ形もよく使われる。

将棋AIでの位置づけ

手の並べ替えは単独で最善手を決める技術ではないが、 探索効率への影響が非常に大きい。

特に、

と組み合わせると重要性がさらに増す。

注意点

  • 良い順序付けができないと、アルファベータ法の利点が大きく落ちる
  • 計算コストの高い並べ替えは、節約できるノード数と釣り合う必要がある
  • ルート付近と深いノードでは、使う並べ替え手法を変えることも多い

関連項目

参考にしたホームページ