ポケモンカードAIを337回改良して分かったこと|ルールを増やすほどAIは強くなるのか?

AI

「ポケモンカードを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. 1体目が攻撃可能になったら、攻撃を邪魔せず2体目を準備する
  3. 有効なカースドボムのルートを作る
  4. ファントムダイブを遅らせない範囲でマシマシラ+悪エネルギーを準備する
  5. 有効な行動を残したままターンを終了しない

ここから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の考え方はおおむね次のようになりました。

  1. 今ターン勝てるなら勝つ
  2. 今ターン確実にサイドを取れるなら取る
  3. 今ターン可能なファントムダイブを壊さない
  4. 最初のファントムダイブまでの距離を最短化する
  5. 現在のアタッカーを邪魔せず、2体目のドラパルトまでの時間を短縮する
  6. ファントムダイブ、カースドボム、アドレナブレイン、ボスの指令を組み合わせてサイド取得につなげる
  7. 有効な特性やサポートなどを使い切る
  8. 目的を達成したら、意味のない行動を続けない

重要なのは、

「このカードなら、この行動をする」

という命令の集合ではなくなったことです。

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の設計・試行錯誤・検証結果を中心に紹介しています。

大会から提供されたデータや画像などを再配布することを目的とした記事ではありません。

コメント

タイトルとURLをコピーしました