千日手と反復局面

反復局面(Repetitions)は、探索中に同じ局面が繰り返し現れる現象である。 将棋では特に千日手判定に直結するため、探索実装で重要である。

概要

探索では、手順を進めていくうちに以前と同じ局面へ戻ることがある。 このとき、

  • 盤面配置
  • 手番
  • 持ち駒

が同じなら、将棋では同一局面として扱う。

探索器はこれを検出して、

  • 千日手
  • 連続王手の千日手
  • 引き分け相当の扱い

などを判断する必要がある。

どう検出するか

典型的には、手順履歴に沿ってゾブリストハッシュのキーを並べておき、 同じキーが過去に出てきたかを確認する。

bool isRepetition(const std::vector<uint64_t>& history, uint64_t currentKey) {
    for (int i = (int)history.size() - 4; i >= 0; i -= 2) {
        if (history[i] == currentKey) {
            return true;
        }
    }
    return false;
}

同じ手番で比較するため、2 手ずつさかのぼる形が使われることが多い。

将棋特有の注意点

チェスでは三fold repetition だが、将棋では千日手の扱いが異なる。 特に重要なのは、

  • 連続王手の千日手
  • 持将棋
  • ルールセット差

である。

そのため、単に「同じ局面が出たら引き分け値」とするだけでは不十分で、 将棋ルールに合わせた判定が必要になる。

探索上の扱い

反復局面を検出したら、

  • 引き分け値
  • やや文脈付きの値
  • 連続王手なら負け相当

などを返す実装が考えられる。

ここは GUI や大会ルールとの整合も重要である。

将棋AIでの位置づけ

将棋では、受けを続けると同じ局面へ戻ることが比較的起こりやすい。 また、詰み回避や王手ラッシュの探索では、反復検出がないと無限ループ的な挙動になりやすい。

そのため、

を組み合わせた実装が重要である。

注意点

  • キー衝突は理論上ありうるので、完全一致判定には注意が必要
  • 連続王手の千日手は通常の千日手と同じ扱いではない
  • ルール差がある環境では値の返し方を調整する必要がある

関連項目

参考にしたホームページ