AIに対戦させる実験では、ローカルシミュレーターを回すとすぐに勝率が出る。

最初はこれを見て、勝率の高いデッキや方針を残していけばよいと思っていた。ところが、ローカルで勝つものが実際のラダーで勝つとは限らなかった。

むしろ、手元の評価が良いものほど実戦結果が悪いケースもあった。

まず提出までの道を作る

最初にやったのは、Kaggle上で動かすためのランタイムと提出スクリプトを揃えることだった。

ローカルでエージェントを動かす、対戦ログを保存する、提出する、提出結果を記録する、という流れを先に通した。環境更新後は Docker に寄せるより、ネイティブ実行に切り替えた方が扱いやすかった。

この段階では、まだ強い戦略を作ったというより、測定できる場所まで持っていっただけだった。

ローカル評価と実戦評価が逆になる

ローカルの総当たりや重み付きの対戦表を作り、実際のリプレイ結果とも比較した。

すると、ローカル勝率をそのまま実戦の強さとして扱うのは危ないことが分かった。ローカルシミュレーターでは、合法手を選べるか、事故らずに動けるか、決めた展開を再現できるかは見える。

一方で、実際のラダーには相手の分布、プレイのテンポ、未知のデッキ、ログには残りにくい選択の偏りがある。ここをローカルだけで再現しようとすると、シミュレーター向けの最適化になってしまう。

なので、ローカル評価の役割を「強さの順位付け」から「明らかなバグや合法性の確認」に下げた。強さの最終判定は、提出してリプレイを見るしかなさそうだった。

複雑なエージェントを小さくする

次に、対戦中の判断をたくさん詰め込んだエージェントを見直した。

最初は、相手の状況に応じて細かく分岐する、1000行近いパイロットを書いていた。ローカルでは賢そうに見える。でも実戦に出すと、判断が増えた分だけ変な分岐も増える。

そこで、セットアップを優先して、攻撃は最後にする単純な方針へ置き換えた。コードは170行程度まで小さくなった。

これを実ラダーに出したところ、複雑な方より良いスコアになった。さらにリプレイ上の12,204個の判断点で、デッキを変えても同じテンプレートの挙動になることを確認した。

もちろん、単純な方針がいつでも勝つわけではない。ただ、細かい判断を増やすことと、実戦で強くなることは別だと分かった。

エラーとタイムアウトを数える

勝率だけを見ると、たまたま勝ったのか、実装が安定しているのか分からない。

そのため、ローカルのラダー形式ベンチマークでは、勝敗とは別にエラーとタイムアウトを記録した。880ゲームを回した時点では、エラーもタイムアウトも0件だった。

勝てるかどうか以前に、止まらず最後まで動くかは重要なので、これは別の指標として残しておくことにした。

7月に入ってからは、実際の上位帯の分布も調べ、上位アーキタイプを追加したローカル総当たりへ広げた。ここでも、ローカルの順位をそのまま信じるのではなく、実戦へ出す候補を選ぶための材料として使っている。

おわり

AI対戦では、シミュレーターを良くすると、シミュレーターに対して良いものが作れてしまう。

ローカル評価は必要だけど、役割を限定した方が良かった。合法性、再現性、エラーの確認には向いている。実際の強さは、実戦に出して結果とリプレイを見る。

いったん複雑にしたエージェントを、単純なテンプレートに戻したのも面白かった。たくさん考えるより、測れるところまで出して、実際の失敗を見た方が次の手がかりになるみたいだ。