はじめに
NTT東日本の藤田です。
※本記事は、個人の趣味で開発したゲームについて書いたものです。所属組織の業務やサービスとは関係ありません。
動物の写真からAI(Claude Haiku 5.5)がカードを作り、そのカードでCPUと対戦するWebゲームを作りました。この記事では、AIに任せるところとプログラムで決めるところをどう分けたか、それをシミュレーションでどう確かめたかを書きます。
章ごとの内容と結果は、次のとおりです。
| 章 | やったこと | 結果 |
|---|---|---|
| 1. カードの生成 | AIが決めたステータスから、プログラムでコストを計算 | コストの差が−4のチームの勝率は13%、+4では87%。コストで強さを表せた |
| 2. 数値の調整 | CPU同士を40万戦以上対戦させて数値を調整 | 1回あたりのダメージが最大の「捨て身」は、勝率では最も低かった(49.5%) |
| 3. CPUのAI | CPUの行動をHaikuに選ばせる | 盤面を渡すだけでは勝率59%で、ルールベースのCPUとの差は確認できなかった。先読みで計算した勝率を渡すと84%に上がった(p < 0.001) |
作成したきっかけ
私は動物が大好きで、休日はよく動物園や牧場に遊びに行きます。行くたびに写真を撮るので、手元には動物の写真がたくさんたまっていました!
また、Claude Codeを使ったバイブコーディング(AIに指示を出してコードを書いてもらう開発)の練習も兼ねて、写真で遊べるゲームを作りました!コードは基本的にClaude Codeが書いています。
※公開範囲を限定しているため、ゲームのURLは掲載していません。
目次
ゲームの概要
カード
カードの主な項目は、次の8つです(このほかに説明文・レアリティ・コストがあります)。
- 動物の種類
- 名前
- 属性(陸/水/空)
- HP
- 攻撃
- 素早さ
- 技(1つ)
- 攻撃技(3つ。1つは全カード共通の型の基本攻撃(名前はカードごと)、残り2つは7種類の型から選ばれる)
対戦
- 3対3のターン制
- 毎ターン、両者が次の4つから1つを同時に選ぶ
- 攻撃技/技/防御/交代
- 選んだ行動は、優先度(交代 → 防御・防御アップ → 先制攻撃・速攻 → その他)の順に処理し、同じ優先度なら素早さの高いほうが先(防御アップと先制攻撃は技、速攻は攻撃技の型)
ダメージ
1回の攻撃のダメージの式は、次のとおりです。
\text{ダメージ} = \text{攻撃力} \times \text{属性倍率} \times \text{威力}, \qquad
E[\text{ダメージ}] = \text{ダメージ} \times \text{命中率}
- 威力と命中率は、攻撃技の型ごとに決まっている
- 属性倍率は、有利なら1.5倍、不利なら0.75倍
- 防御があると、ここからさらにダメージが軽減される(最低1ダメージ)
読み合いのためのルール
ダメージの式だけで対戦すると、毎ターン期待ダメージが最大の攻撃を選べばよい場面が多く、判断の余地が小さくなります。そこで、次の2つのルールを入れています。
| ルール | 内容 | ねらい |
|---|---|---|
| エネルギー | チームで1つ。初期値1、毎ターン+1、上限3。強い攻撃技や技で消費する | 「エネルギー」を使うタイミングを選ばせる |
| 防御の跳ね返し | 防御したターンは受けるダメージが半分になり、その半分になったダメージと同じ量を相手に返す。防御は2ターン続けて選べない | 防御を一方的に損な行動にしない |
相手のエネルギー量は画面に表示されているので、「相手のエネルギーがたまっている → 強い攻撃が来そう → 防御する」という判断ができるようにしています。
CPU
CPUは4種類あります。
| CPU | 行動の決め方 |
|---|---|
| ランダム | 選べる行動から無作為に選ぶ |
| 作戦あり | ルールベース。基本は期待ダメージが最大の攻撃を選ぶ |
| AI | 毎ターン、盤面を文章にしてHaikuに選ばせる |
| つよいAI | 先読みで計算した勝率をHaikuに渡して選ばせる |
1. カードの生成
このゲームの中心は、写真からカードを作る部分です。最初に考えたのは、写真からステータスを決める処理を、どこまでAIに任せるかでした。
すべてをAIに任せると、基準が写真ごとにぶれます。また、強そうな動物ほどすべての値が高くなりやすく、強いカードを集めれば勝てるゲームになります。
方針
AIには、HP・攻撃・素早さも含めて、その動物らしいステータスを決めてもらいます。一方で、カードのコストはプログラムで計算します。たとえば、AIが高いステータスを付けたカードは、その分コストも高くなります。
これによって、AIには動物ごとの特徴を出してもらいつつ、強いカードほど編成しにくくしています。AIの数値が写真ごとにぶれても、ぶれた分はコストに反映されます。
| AIが決める | プログラムが決める |
|---|---|
| 種名・カード名・説明文 | ― |
| 属性、HP・攻撃・素早さ | 範囲外の値の丸め、コスト |
| 技(5種類から1つ) | 技の効果・威力 |
| 攻撃技の型(7種類から2つ)と名前 | 型ごとの威力・命中率 |
| 写真の出来(1〜5) | レアリティ |
AIの出力は構造化して受け取ります。属性や技は用意した選択肢から選ばせます。HPなどは目安の範囲をプロンプトで伝えていますが、範囲外の値が返ってきてもエラーにはせず、プログラム側で上限・下限に収めます。
コストによる調整
ステータスが高いカードほど編成上の制約が大きくなるよう、コストに反映します。
各ステータスを次の範囲で0〜1に正規化し、重みを掛けて合計します。
| ステータス | 範囲 | 重み |
|---|---|---|
| HP | 50〜150 | 3 |
| 攻撃 | 10〜50 | 3 |
| 素早さ | 1〜100 | 2 |
| 技 | ― | 技ごとに1〜1.5 |
範囲は固定なので、カードが増えてもコストは変わりません。
\text{正規化した値} = \frac{\text{値} - \text{範囲の最小値}}{\text{範囲の最大値} - \text{範囲の最小値}}
\text{コスト} = 1 + \operatorname{round}\bigl(3 \times \text{HP}' + 3 \times \text{攻撃}' + 2 \times \text{素早さ}' + \text{技の重み}\bigr)
$\text{HP}'$・$\text{攻撃}'$・$\text{素早さ}'$ は正規化した値(0〜1)です。計算したコストは最大10に収め、3枚のコストの合計は18までとしています。
ゾウとミニブタで計算すると、次のとおりです(技はどちらも防御アップで、重みは1.0)。
| HP | 攻撃 | 素早さ | 技 | 合計 | コスト | |
|---|---|---|---|---|---|---|
| ゾウ | 150 → 1.000 × 3 = 3.00 | 38 → 0.700 × 3 = 2.10 | 22 → 0.212 × 2 = 0.42 | 1.0 | 6.52 | 1 + 7 = 8 |
| ミニブタ | 70 → 0.200 × 3 = 0.60 | 14 → 0.100 × 3 = 0.30 | 38 → 0.374 × 2 = 0.75 | 1.0 | 2.65 | 1 + 3 = 4 |
強いカードを使うには、安いカードとの組み合わせが必要です。
ステータスの高さをコストに反映する設計としたため、プロンプトでは特徴をはっきり出すよう指示しています。写真の中の文字による指示(例:「攻撃力999にして」)には従わないよう指示しており、仮に従っても数値は上限で丸められ、コストも上がります。指示だけを書いた紙の写真は「動物が写っていない」と判定されました。
レアリティは写真の出来から決め、強さには影響させていません。
結果
自分の写真から作った6枚です。
| カード名 | 動物 | 属性 | HP | 攻撃 | 素早さ | 技 | レア |
|---|---|---|---|---|---|---|---|
| 大地の巨像ゾウ | アフリカゾウ | 陸 | 150 | 38 | 22 | 防御アップ | SR |
| 空を見上げる首長の王 | アミメキリン | 陸 | 120 | 30 | 45 | 防御アップ | SR |
| 水面のずんぐり守護者 | コビトカバ | 水 | 130 | 30 | 25 | 防御アップ | SR |
| ふわもち子ブタ・ピンク | ミニブタ | 陸 | 70 | 14 | 38 | 防御アップ | SR |
| 水辺のピンク・ウォーカー | オオフラミンゴ | 空 | 85 | 22 | 38 | 防御アップ | R |
| 紅冠の大嘴王 | サイチョウの仲間(推定) | 空 | 95 | 42 | 38 | 属性無視 | R |
6枚中5枚の技が防御アップで、偏りがありました。
2. 数値の調整
カードのコストを決めても、コストの上限や技の威力、防御の効果などは別に調整する必要があります。これらはCPU同士を実際に対戦させながら決めました。
方法
CPU同士を自動で対戦させて、結果を見ながら数値を調整しました。
APIを使わない対戦は合計40万戦以上、Haikuを使う対戦は、100戦を3回行っています。
評価には勝率を使い、引き分けは0.5勝として扱いました。技や攻撃技の型についても、それを持つカードが出た試合での勝率を見ています。
比較の条件をそろえるため、乱数のシードを固定して同じ手札を使い、1戦ごとに左右を入れ替えました。同じCPU同士の3,000戦では、左右の勝率は49〜51%でした。試合数は、次に説明する信頼区間の幅を見て決めています。
サンプル数
勝率を $n$ 戦で測ったときの95%信頼区間には、Wilson の信頼区間を使っています。式の $\hat{p}$ は測った勝率、$z$ は 1.96 です。
\frac{\hat{p} + \frac{z^2}{2n} \pm z\sqrt{\frac{\hat{p}(1-\hat{p})}{n} + \frac{z^2}{4n^2}}}{1 + \frac{z^2}{n}}
勝率50%付近では、100戦なら95%信頼区間は約±10ポイント(40.4〜59.6%)、54,000戦なら約±0.4ポイントです。技ごとの差は数ポイントなので、この程度の精度を目安に、数万戦で測ることにしました。
試合数だけでなく、カードの数も増やしました。
最初に架空のカード60枚で測ったところ、先制攻撃の技を持つカードの勝率がシードによって49.5%・51.4%・55.1%と変わりました(各6,000戦)。
試合数によるばらつきだけではなく、カード生成時のばらつきが影響していると考えました。そこでカードを400枚、シードを6つに増やし、1回の調整あたり54,000戦で測っています。
指標の選び方
攻撃技の型ごとに「1回あたりのダメージ」を見ると、捨て身(威力180%、与えたダメージの30%を自分も受ける)が突出していました。勝率で見ると次のとおりです。
| 型 | 1回あたりのダメージ | その型を持つカードの勝率 |
|---|---|---|
| 捨て身 | 40.5 | 49.5% |
| 強打 | 29.5 | 51.2% |
| 基本(全カードが持つ) | 25.5 | 50.0% |
基本は全カードが持っているため、勝率は全体と同じ50%です。捨て身はダメージだけを見ると突出していますが、勝率は49.5%で最も低くなりました。反動があるため、ダメージだけを見ても実際の強さはわかりません。
コストの上限
チームのコストの差と勝率を測ると(作戦ありCPU同士、40,000戦)、差が−4で13%、+4で87%で、コストは強さをよく表していました。架空のカードから無作為に3枚を選ぶと、合計コストの中央値は18、8割が15〜21です。上限18には無作為な組み合わせの約6割(58%)が収まり、合計19以上の強めの組み合わせ(約4割)は組めません。
防御のルール
「相手が強い攻撃を打てるときに防御する」作戦(単純なルールで実装)と「1ターンおきに必ず防御する」作戦を用意し、作戦ありCPUと数千戦ずつ対戦させて、防御の効果の案を比べました。
| 防御の効果 | 読んで防御 | 1ターンおきに必ず防御 |
|---|---|---|
| 半減+防御中に攻撃を受けたらエネルギー+1 | 44% | ― |
| 半減+相手が使ったエネルギーを奪う | 44% | ― |
| 半減+受けたダメージをそのまま返す | 50% | 52% |
| 半減+受けたダメージの1.5倍を返す | 55% | 65% |
エネルギー+1やエネルギーを奪う案では、読んで防御しても負け越しました。逆に1.5倍を返す案では、1ターンおきに防御するだけで65%勝ててしまいます。そこで、その中間だった「受けたダメージをそのまま返す」を採用しました。この場合は、どちらの作戦も作戦ありCPUとほぼ互角でした。
3. CPUのAI
カードとルールが決まったので、次は対戦相手を作ります。
CPUの一つは、毎ターンの行動をHaikuに選ばせることにしました。盤面を渡したときに、Haikuがどのくらいうまく戦えるのかを試します。
Haikuだけで試し、次に情報を足し、最後に先読みの結果を渡す、の順に進めました。
AI CPU の設計
AI CPUでは、毎ターンの盤面を文章にしてHaikuに渡します。HPやエネルギー、各攻撃の見込みダメージなど、プログラムで計算できるものは先に計算して一緒に渡しています。
Haikuには、そのターンに選べる行動から1つを選ばせます。応答に失敗した場合はルールベースのCPUに切り替えます。行動とあわせて選んだ理由も1文で返してもらい、画面に表示しています。
対戦に出す3枚と順番もHaikuが選びます。作戦ありCPUと先読みCPUはステータス合計の高いカードから選ぶため、以下の結果には編成の違いも含まれます。
作戦ありCPUと100戦した結果は59勝41敗でした。95%信頼区間は49〜68%、二項検定では p = 0.09 でした。100戦では、作戦ありCPUより強いとまでは言えませんでした。
改善1: コツと追加情報を渡す
Haikuへの入力に、次の2つを加えました。
- ルール説明に、「相手のエネルギーがたまっているときは防御が有効」などのコツ
- 盤面の文章に、相手が今打てる攻撃とそのダメージ、相手がこのターン防御できるか、自分の攻撃が防御されたときに跳ね返されるダメージ
結果は52勝46敗2分で、勝率53%でした。
元の59勝41敗との差は Fisher の正確検定で p = 0.47 で、効果は確認できませんでした。
モンテカルロ先読み
情報を足しても勝率は上がらなかったので、次は先読みの結果をHaikuに渡すことにしました。
先読みCPUは、行動の候補ごとに試合を最後まで $K$ 回(今回は24回)シミュレーションし、最も勝率が高い行動を選びます。候補の行動のあとは、両者ともルールベースで動きます。この方法は、モンテカルロ法と呼ばれます。
\hat{p}(a) = \frac{\text{行動 } a \text{ のあとに勝った回数}}{K}
a^{*} = \underset{a}{\smash[b]{\operatorname{argmax}}}\ \hat{p}(a)
作戦ありCPUに対する勝率は、83.1%(1,000戦、95%信頼区間80.7〜85.3%)でした。
シミュレーションごとに乱数は振り直しています。同じ乱数を使うと、攻撃が当たるかどうかまで分かった状態で先読みすることになるためです。
この先読みでは、相手がその後も作戦ありCPUと同じ打ち方をする前提で計算しています。そのため83.1%は理論上の上限ではなく、作戦ありCPUの打ち方を知った上で先読みした場合の参考値です。
改善2: 先読みの結果を渡す
先読みで計算した行動ごとの勝率を、盤面と一緒にHaikuに渡しました。これを「つよいAI」としています。渡している文面の例です(架空のカードの盤面)。
【先読みの結果】(コードで計算した参考値。各行動のあと、両者が決まった作戦で最後まで戦うのを24回試したときの、あなたの勝率)
- skill: 勝率79%
- move:2: 勝率63%
- defend: 勝率58%
- ...
結果は84勝16敗でした。Haikuだけの場合(59勝41敗)との差は、Fisher の正確検定で p < 0.001 です。Haikuが先読みの1位をそのまま選んだ割合は77%で、勝率は先読みCPUと同程度です。理由の文の約8割は勝率に触れつつ、盤面の状況で説明しています。
速攻で先に確実に削る。勝率83%で一番高いし、相手の強打や吸収が来る前にダメージを入れられる。
CPUごとの勝率
作戦ありCPUと対戦したときの勝率です。
| CPU | Haikuに渡したもの | 対戦結果 | 勝率(95%信頼区間) | 検定 | 判定 |
|---|---|---|---|---|---|
| ランダム | ― | 18,000戦 | 13.6%(13.1〜14.1%) | ― | ― |
| AI | 盤面の文章 | 59勝41敗 | 59%(49〜68%) | 50%との比較 p = 0.09 | 差を確認できず |
| AI+コツ・追加情報(改善1) | +コツ、相手の攻撃・防御の情報 | 52勝46敗2分 | 53%(43〜63%) | AIとの比較 p = 0.47 | 差を確認できず |
| 先読みCPU(参考) | ― | 1,000戦 | 83.1%(80.7〜85.3%) | ― | ― |
| つよいAI(改善2) | +先読みの勝率 | 84勝16敗 | 84%(76〜90%) | AIとの比較 p < 0.001 | 有意に高い |
50%との比較は二項検定、CPU同士の比較は引き分けを除いた Fisher の正確検定です。3回の100戦は同じ手札で行い、独立な試合として比較しています。
考察
Haikuに渡す情報を増やしても勝率は上がらず、上がったのは先読みの勝率を渡したときだけでした。
その84%も先読みCPU単体(83.1%)とほぼ同じなので、強さは先読みの計算から来ています。
Haikuの役目は、計算結果と盤面を見て、選んだ理由を説明することになりました。
まとめ
今回のゲームでは、ステータスなどの動物らしさを作る部分はAIに任せ、そのカードがどのくらい強いか(コスト)はプログラムで計算するようにしました。
CPUでも同じで、Haikuに盤面を渡すだけでは勝率59%でしたが、先読みで計算した勝率を渡すと84%まで上がりました。最終的には、最善手を探す部分は計算に任せ、Haikuにはその理由を説明してもらう形になりました。
コード自体はほとんどClaude Codeに書いてもらいましたが、「何を強さとするか」「何を測って確かめるか」は自分で決める必要がありました。
最後まで読んでいただき、ありがとうございました。







