ガイスターの紫駒版endgame tablebaseを公開しました

前回の記事では完全情報版tablebaseを公開したことをお知らせしましたが、今回はそれに紫駒版endgame tablebaseを構築するコードを追加しました。GATクライアント対応ソフトにもそれを使う機能を追加し、tablebaseそれ自体もHuggingFaceに追加しました。

GATクライアント対応ソフトについて

https://github.com/eukaryo/Unweaver-TwoColorEscapeBoardGameAI/blob/main/geister_stdio_baseline_player.cppgithub.com

このcppファイルがGATクライアント対応ソフトのエントリーポイントです。tablebaseをprobeする方法、必勝法を検出するアルゴリズム、クライアントとやりとりするプロトコル実装なんかを紹介するためだけのソフトという位置付けで作っています。大会に出たときより弱いです。現在の行動パターンは以下の通りです:

  1. 即座に脱出勝利可能な場合は脱出勝利の手を指します。
  2. proven_escape_move関数。自分の青駒のうちどれかを最速で脱出させれば必ず勝てる局面を、alpha-beta探索とかではなくDijkstra法のようなアルゴリズムで高速に判定します。false positiveはありません(この関数が指し手を返した場合は必ずその指し手で勝てます。200手引き分け以外は)false negativeは許容します。std::nulloptが返されたら次に進みます。
  3. purple_winning_move関数。紫駒tablebaseをprobeして、現在局面が紫駒必勝だった場合は2手読みして、最短で勝てるとされる指し手を求めて返します。2手読みする理由は、「紫駒側のtablebase」を見ないからです。(構築はしますが、probeはしません)std::nulloptが返されたら次に進みます。
  4. confident_player関数。1手読みした先の局面について完全情報tablebaseをprobeして、相手駒の色配置のうち1つ以上の色配置パターンで必勝であるような指し手が存在する場合、必勝であるような色配置パターンの数が最大の指し手を返します。同率タイの手が複数ある場合は全て返します。指し手が返されたら、その中からランダムに1手選びます。std::nulloptが返されたら次に進みます。
  5. random_player関数。全合法手のなかから完全ランダムに指し手を選びます。

module:private; について

このGitHub repoのコードではC++20のmoduleという機能を多用しています。C++20 moduleは昔からあるヘッダとソースファイルに分離する慣習の代替を目指す仕組みです。わたしがC++20のmoduleを試している理由は、module:private;という言語機能があるからです。module:private;を書くと、そこからファイル末尾までの全てがprivate module fragmentになります。private module fragmentはそのモジュールをimportする他の翻訳単位からは全く見えず、到達不能になることが言語仕様により完全に保証されます。加えて、private module fragmentを含むモジュールユニットはそのモジュール唯一のモジュールユニットでなければならないので、このケースでは同じnamed moduleに属する別のmodule unitやpartitionがどこか別ファイルに存在する可能性も排除されます。
これってすごくて、今回わたしはLLMによるvibe codingで可能な限りやっていくことにしているんですが、LLM目線で「ファイル先頭から順番に読み進めていったとき、module:private;が出たらその後ろを読まなくても、少なくともimporterから到達可能なインターフェースは100%把握できる」ことが確定します。これは他の言語機能では代替できません。例えば無名名前空間では対応するカッコ閉じまでしか保証されませんから、"namespace {" のカッコ開きに対応する閉じカッコがどこにあるのか確認する手間が少なくとも生じるでしょう。言語仕様によってLLMのコンテキストが無駄に食い潰されないことでLLMのポテンシャルを引き出せるかもしれないと思い採用しています。(注:真偽不明な個人の感想です)
C++20 moduleの現状最大の欠点はVS Codeの支援機能が不安定なところです。そのために一時期採用を躊躇していたんですが、重要な事実を見落としていました。コードエディタの支援機能が役に立つのは、自分の指でコードを書くか、自分の目でコードを読むときだけです。わかりますね?