「ポケモンカードをAIにプレイさせたら、どこまで強くできるのか?」
そんな試みとして、私は自分のMac上にポケモンカードの対戦環境を作り、AI同士で対戦させながら改良を続けています。
そして今回、Kaggleで開催された「Pokémon TCG AI Battle Challenge」のStrategy部門に参加しました。
そこで開発したのが、ドラパルトexを中心としたAIです。
最初は、
「人間が考える強い動きを、そのままAIに教えればいい」
と思っていました。
ところが実際に作ってみると、そう簡単ではありませんでした。
最終的にAIは337回以上の改良を重ねることになります。
この記事では、完成したプログラムそのものではなく、
337回の試行錯誤で、AIの考え方がどう変わっていったのか
を紹介します。
最初のAIは「人間のルール」を教えるところから始まった
最初は非常に単純でした。
例えば、
- 進化を優先する
- ドラメシヤを育てる
- ファントムダイブを優先する
- エネルギーを無駄にしない
といった、人間なら当たり前に考えそうなルールをAIに追加していきました。
最初のうちは、これでAIが賢くなったように見えます。
ところがルールを増やしていくと、別の問題が起こりました。
ある状況を改善するためにルールを追加すると、別の状況でおかしな行動をする。
そのおかしな行動を修正するために、さらに例外ルールを追加する。
すると、また別のところがおかしくなる。
つまり、
ルールを増やせば増やすほどAIが賢くなるわけではなかった
のです。
衝撃だった「スボミーにエネルギー3枚」
開発途中、AIがかなり不思議な行動をしました。
スボミーにエネルギーを3枚付けたのです。
スボミーは攻撃するためにエネルギーを必要としません。
普通に考えれば、明らかにおかしな行動です。
そこで、
「スボミーにエネルギーを付けない」
というルールを追加したくなります。
しかし調べてみると、原因は戦略ではありませんでした。
AIがカードの攻撃情報を正しく取得できていなかったのです。
V5では213回の判定すべてで、攻撃準備状態を示す attack_readiness が0になっていました。
原因は CardData.attacks に攻撃情報そのものが入っていると思い込んでいたこと。
実際には攻撃情報ではなくAttack IDが入っていました。
V6で実際の攻撃情報を取得するよう修正すると、対象となる56状態のうち54状態で正しく攻撃準備を判断できるようになりました。
ここで大きな教訓を得ました。
AIがおかしな行動をしたとき、すぐに新しいルールを追加してはいけない。
まず、
「AIは正しい情報を見て判断しているのか?」
を確認する必要があります。
「全部を点数化する」方法にも限界があった
次に取り入れたのが、行動を点数化する方法です。
例えば、
「この行動は重要だから高得点」
「この行動は今やるべきではないから減点」
というように、それぞれの行動に評価値を与えます。
V45~V68あたりでは、この方式をかなり増やしました。
ところが、ここにも問題がありました。
進化する。
特性を使う。
エネルギーを付ける。
ボスの指令を使う。
ダメカンを移動する。
こうした行動が、同じ土俵で点数を競ってしまいます。
その結果、
「エネルギーを付ける前に進化してほしい」
「ドラメシヤをドロンチに進化させてほしい」
「ドロンチに進化したのに特性を使ってくれない」
といった問題が起きました。
AIの判断を2階層に分けた
そこでV69付近から、AIの判断を大きく2種類に分けるようになりました。
基本となる行動
盤面を作る、進化する、重要な特性を使う、カードを探す、サポートを使う、エネルギーを管理する。
戦術的な行動
カースドボム、アドレナブレイン、ボスの指令、ファントムダイブのダメカン配置など、その場の状況によって変化する判断です。
ここでの考え方は、
「絶対に必要な基本行動と、状況によって変わる戦術を、すべて同じ点数競争に参加させない」
というものです。
これはAIの構造を考えるうえで、大きな転換点になりました。
「良い盤面」ではなく「ファントムダイブまであと何手?」
そしてV152付近から、AIの考え方をさらに変えました。
それまでは、
「この盤面は強いか?」
を評価していました。
しかし「強い盤面」というのは曖昧です。
そこで、
「あと何手、何ターンでファントムダイブを撃てるのか?」
を考えるようにしました。
優先順位を単純化すると、
今ターンにファントムダイブ
> 次ターンにファントムダイブ
> 理想的な盤面を作る
です。
V191では、さらに具体化しました。
- 最初のファントムダイブまでの行動数を減らす
- 1体目が攻撃可能になったら、攻撃を邪魔せず2体目を準備する
- 有効なカースドボムのルートを作る
- ファントムダイブを遅らせない範囲でマシマシラ+悪エネルギーを準備する
- 有効な行動を残したままターンを終了しない
ここからAIは、
「このカードは強いか?」
ではなく、
「この行動によって目的までの距離がどれだけ短くなるか?」
を考える方向へ変わっていきました。
600戦して分かった「カードを使った=良い行動」ではない
V209では600戦のテストを行いました。
結果は、
156勝444敗、勝率26.0%
でした。
そこで「夜のタンカ」の使い方を詳しく調べました。
単純に、
「夜のタンカを使った試合の勝率」
だけを見ると、あまり良い結果ではありません。
しかし考えてみると当然です。
夜のタンカは、盤面が崩れたときなど、不利な状況で使われることも多いからです。
そこで、
炎エネルギー・超エネルギー・ドロンチ・ドラパルトex
といった、ファントムダイブにつながるパーツを回収したケースに絞りました。
該当したのは114回。
そのうち43回、約37.7%で、次の自分のターン終了までにファントムダイブへつながっていました。
さらに、すぐファントムダイブにつながったケースでは勝率30.23%。
つながらなかったケースでは9.86%でした。
ここで評価方法を変えました。
「このカードを使ったか?」
ではありません。
「この行動によって、目的まで何ターン短縮できたのか?」
を見るようにしたのです。
勝率だけ見ていたらAIを間違った方向へ進化させる
もう一つ重要だったのが、勝率の扱いです。
例えばV322。
ある500戦では、
226勝500戦=45.2%
でした。
「かなり強くなった!」
と思います。
ところが同等のコードをもう一度テストすると、
176勝500戦=35.2%
さらに別のテストでは、
204勝500戦=40.8%
でした。
同じようなAIでも、これだけ結果が変動します。
そのため、短期間の勝率だけで、
「この改良は成功!」
と判断するのをやめました。
勝率以外にも、
- 一度もファントムダイブできなかった試合数
- ファントムダイブを撃った回数
- 平均取得サイド枚数
- 2体目のアタッカーを準備できたか
- 実際のリプレイで変な行動をしていないか
などを見るようにしました。
実際、数字だけなら良さそうに見える改良でも、リプレイを見ると明らかにおかしいことがありました。
勝率が上がった=AIが賢くなった
とは限らないのです。
そして「ファントムダイブを撃つAI」から卒業した
開発を続けると、また新しい問題が出てきました。
ファントムダイブは撃てる。
しかも何回も撃てる。
それなのに負ける。
つまり、問題が変わったのです。
それまでの目標は、
「どうすればファントムダイブを撃てるか?」
でした。
しかし本来のポケモンカードの目的は、ファントムダイブを撃つことではありません。
相手より先にサイドを6枚取ることです。
そこでAIの目標を、
「ファントムダイブを撃つ」
から、
「ファントムダイブをどうサイド6枚に変換するか」
へ変更しました。
「今の1枚」と「未来の盤面」のどちらを取る?
ここも面白い問題でした。
例えば、
ヨノワールのカースドボム130ダメージ
+
ドラパルトexのファントムダイブ200ダメージ
=330ダメージ
というルートがあります。
この330ダメージで相手の重要なポケモンを確実に倒せるとします。
一方で、2体目のドラパルトを育てるという選択肢もある。
以前のAIは未来の盤面を重視しすぎることがありました。
そこでV336では、
「未来の盤面を良くするためだけに、今ターン確実に取れるサイドを捨てない」
という考え方を取り入れました。
これは、
「攻撃を最適化するAI」
から、
「サイドを取るルートを最適化するAI」
への変化でもあります。
ベンチの空きまで「資源」として考える
V337では、さらに細かな部分まで考えるようになりました。
以前のAIはドラメシヤを置けるだけ置こうとする傾向がありました。
しかし、
ドラメシヤ2系統+ヨマワル
まで準備できている状態で3体目のドラメシヤを置くと、最後のベンチ枠を使ってしまいます。
すると後からマシマシラなどを出したくても出せません。
そこでV337では、
「何も置いていないベンチ枠にも価値がある」
と考えるようにしました。
必要な盤面が完成したら、無理にポケモンを置かず、将来のための空き枠を残します。
最終的なAIの判断順序
337回以上の改良を経て、AIの考え方はおおむね次のようになりました。
- 今ターン勝てるなら勝つ
- 今ターン確実にサイドを取れるなら取る
- 今ターン可能なファントムダイブを壊さない
- 最初のファントムダイブまでの距離を最短化する
- 現在のアタッカーを邪魔せず、2体目のドラパルトまでの時間を短縮する
- ファントムダイブ、カースドボム、アドレナブレイン、ボスの指令を組み合わせてサイド取得につなげる
- 有効な特性やサポートなどを使い切る
- 目的を達成したら、意味のない行動を続けない
重要なのは、
「このカードなら、この行動をする」
という命令の集合ではなくなったことです。
AIに、
「最終的に何を達成したいのか」
を評価させる方向へ変わりました。
V337を500戦させた結果
最終候補となったV337を、同じ固定テスト環境で500戦させました。
結果は、
235勝 / 500戦
勝率47.0%
でした。
100戦ごとの勝利数は、
52勝 → 43勝 → 41勝 → 45勝 → 54勝
でした。
さらに、
- ファントムダイブ0回:81/500試合
- ファントムダイブ2回以上:376/500試合
- 平均ファントムダイブ回数:2.288回
- 平均取得サイド:3.382枚
という結果になりました。
ただし、この47.0%を、
「このAIの本当の勝率は47%」
とは考えていません。
同じようなコードでも結果にかなりのばらつきがあったからです。
337回改良して一番感じたこと
今回の開発で一番大きかったのは、
「ルールをたくさん追加すればAIが賢くなるわけではない」
ということでした。
最初は、
局所的なルール
から始まりました。
それが、
局所ルール
↓
行動スコア
↓
基本行動と戦術判断の分離
↓
最初のファントムダイブまでの距離
↓
2体目のアタッカーまでの距離
↓
サイド6枚までの距離
と変化していきました。
最終的に評価したいのは、
「このカードは何点か?」
ではありません。
「この行動によって、相手より先にサイドを6枚取るまでの距離がどれだけ短くなるのか?」
です。
次に作りたいもの
まだAIは完成していません。
次にやりたいのは、
Six-Prize Route Evaluator
です。
ファントムダイブの200ダメージ。
ベンチへのダメカン。
アドレナブレイン。
カースドボム。
ボスの指令。
2体目のアタッカー。
そして、どのポケモンを倒せば何枚サイドを取れるのか。
これらを個別に評価するのではなく、
「現在の盤面から、どういう順番で相手を倒せばサイド6枚に最短で到達できるか」
を一つのルートとして評価させたいと思っています。
「良い行動」を探すAIから、
「勝利までのルート」を探すAIへ。
まだまだ改良は続きます。
Kaggleについて
今回のAIは、Kaggleで開催された「Pokémon TCG AI Battle Challenge」のStrategy部門に向けて開発・検証したものです。
この記事では、私自身が行ったAIの設計・試行錯誤・検証結果を中心に紹介しています。
大会から提供されたデータや画像などを再配布することを目的とした記事ではありません。


コメント