TadaoYamaokaの開発日記

個人開発しているスマホアプリや将棋AIの開発ネタを中心に書いていきます。

【バイブコーディング】レトロ戦略ゲームを作る その5(AIを強くする)

前回、マップの保存/読み込みに対応して、ゲームボーイウォーズのマップを変換して取り込めるようにした。
しかし、AIが弱すぎてゲームとして楽しめなった。

今回は、AIを強化する。

ターン制戦略ゲームのAI

ゲームボーイウォーズのようなターン制戦略ゲームは、ユニットの数が多く、行動の選択が広いため、将棋AIのような全探索をするのが難しい。
また、遠くの未占領の都市を数ターンかけて目指すような長期的な目標が必要になる。

自ターンのみでも、最大40ユニットの探索が必要で、これを数ターン分探索しないと、結果が見えない。
将棋AIでも探索深さは20から30程度のため、これを探索で行うのはほぼ不可能である。

そのため、ルールベース+評価関数+局所探索の組み合わせで作るのが実用的である。

将来的には、ルールベースは、方策をニューラルネットワークが学習して、評価関数もニューラルネットワークの学習にすることができる。

今回は、ゲームボーイウォーズのアルゴリズムを調査して、ルールベースとして組み込み、ルールの重みをSPSAでチューニングすることにする。

ゲームボーイウォーズのAIアルゴリズム

ChatGPTでDeep Researchを行い、ゲームボーイウォーズのAIアルゴリズムを解析したサイトの情報を調査した。

以下のようなアルゴリズムであることがわかった。

基本設計

  • ミニマックスのような深い探索ではなく
    • → ルールベース + ヒューリスティック評価による貪欲法
  • 各ターンで「最もスコアの高い行動」を選択

探索の特徴

  • 基本は 1手読み(浅い探索)
  • 反撃ダメージは内部的に考慮(疑似的に1.5手相当)
  • GBの制約(約4MHz / RAM 8KB)により深い探索は困難

行動決定フロー

  • 各ユニットごとに:
    • 移動可能マスを列挙
    • 攻撃・占領・待機などの候補を生成
  • 各候補をスコア化
  • 最大スコアの行動を選択(貪欲)

評価関数(主な要素)

  • 与ダメージ(敵コスト換算)
  • 撃破ボーナス
  • 被ダメージ・リスク
  • 占領価値(特に首都は高評価)
  • 生産拠点の制圧・妨害
  • 敵本拠地への接近
  • 危険エリア回避(高IQ時)

重要なヒューリスティック

  • 生産拠点上の敵ユニットを最優先で攻撃
    • → AIの挙動を強く特徴づけるルール
  • 生産妨害(拠点に乗る)も高評価
  • 占領(特に首都)を強く優先

難易度(IQ)の違い

  • IQ100:
    • 単純・攻撃寄り
    • 危険回避が弱い
  • IQ200:
    • 危険回避あり
    • 占領・戦略評価が強化
    • より多くの候補を比較

ルールベース挙動

  • 特定条件でユニット生産が変化(例:対空ユニット)
  • 索敵ON/OFFで視界・行動が変化
  • 占領可能ユニットは限定(歩兵系)

全体的特徴

  • 局所最適に強いが、長期戦略は弱い
  • 囮や誘導に弱い(単純優先ルールのため)
  • 計算量を抑えた設計(GBハード制約に適合)

Codexで実装

ゲームボーイウォーズのAIアルゴリズムの調査結果を入力して、CodexでAIを実装した。
テストプレイを行い、おかしな行動を見つけては修正指示を行った。

与えた指示は、以下のようなものである。

design\aI-analysis-report.md を元にAIを実装してください。
まず、現在のAIの実装(HexFront.AI)を確認してください。
design\aI-analysis-report.mdのアルゴリズムを実装するための方針を立ててください。
それから実装に取り掛かってください。
索敵は無視してよいです。
テストプレイしたところ、AIが歩兵しか生産しないので、何か間違っていないか確認してください。
開始ターンでいきなり戦車Bを1台だけ作ってターンエンドします。定跡では1ターン目は歩兵を作らないと占領地を増やせないので不利です。
戦車Bと装甲車の生産はどのような基準で選択されますか?
調整するパラメータやルールは入っていますか?
相手のユニットを見て、ユニット間のダメージ相性も考慮して加点・減点するルールは入れられますか?
たとえば、装甲車は歩兵に強いので、相手が歩兵ばかりであれば加点し、相手に装甲車がいれば戦車が有利なので戦車に加点します。装甲車、戦車に特化したルールではなく、相手ユニットの状況とダメージ表から汎用的なルールを構築して欲しいです。
以下のルールや仕組みを実装してください。
- 次のターンで相手に占領されないようにブロックするルール
- 次の近くの占領目標に向けて歩兵が分散して目指すルール(同一の目標値に向かわないような重み調整)
- 資金を温存して、現在の状況に適した強い兵器を次ターンに生産することへの加点(現状は戦車Bばかり生産されがち)
- 今後、機械学習でパラメータ調整するので、できるだけ重みはパラメータとして調整できる余地を作る
こちらが歩兵しか生産していないのに、AIは戦車Bを作ってくる。装甲車が作られないのは不自然。パラメータを調整することで、歩兵しかいない場合に、装甲車が優先される余地のある実装になっているか確認してください。
その余地を作るため、TankB/装甲車の固定ボーナスや matchupScore 係数も AiWeights 側へ出して、相性評価の比重を上げられるそのように修正してください。
戦車がダメージ相性のより装甲車を攻撃しに向かわずに、別の方向に向かっているように見受けられます。相性の良い相手を攻撃目標として、移動するルールは入っていますか?
相性の良い相手を攻撃目標として移動することに加点するようなルールを加えてください。遠すぎる相手は相手の移動先が不確実なので考慮すべきではないことに注意してください。パラメータは調整可能としてください。
占領要員は足りている判定のパラメータを調整して、もう少し歩兵が生産が促されるようにしてください。
day <= 2のように固定しきい値にするのではなく、重みとして加算、減点されるパラメータとしてください。
今度は、歩兵生産の圧力が強すぎるようです。生産の空があるのに、歩兵を生産せずにターン終了するのは避けたいが、歩兵しか生産しなくなるのは避けたい。
相手のユニット編成に対して、すでに数が十分なのに同じユニットばかりを作り続けるようになっていないか確認してください。
思考時間改善

デバッグビルドで思考が遅いため、無駄な処理がないか確認を行った。

結果は同じで強さを維持しつつ、効率的な枝刈りできる箇所はありますか?
重複計算削減を行ってください。

実装結果

上記のようにゲームボーイウォーズのAIアルゴリズムをベースに実装して、修正指示することで、遊べるレベルになった。

歩兵で分散して占領したり、拠点に砲台を生産したり、資金をためて戦車Aを生産したりするようになった。

SPSAによるチューニング

ルールベースで実装したアルゴリズムには、以下のようなパラメータがある。
これらを手動で調整するのは難しい。
そこで、チェスAIや将棋AIの探索パラメータチューニングで使用されている、SPSAで自動調整することを試みる。

調整可能パラメータ

全体評価
  • minimumUsefulActionScore: 最善手の点数がこれ未満なら行動せずターン終了しやすくする閾値。
  • strategicMaterialWeight: 盤面全体の総戦力差をどれだけ重視するか。
  • strategicFundsWeight: 現金差をどれだけ重視するか。
  • strategicIncomeWeight: 収入差をどれだけ重視するか。
  • strategicObjectiveProgressWeight: 敵施設への接近度を戦略評価にどれだけ入れるか。
移動と前進
  • mobilityCaptureAdvanceWeight: 占領可能ユニットの前進をどれだけ褒めるか。
  • mobilityCombatAdvanceWeight: 戦闘ユニットの前進をどれだけ褒めるか。
  • cargoCaptureAdvanceWeight: 輸送中の占領ユニット前進をどれだけ褒めるか。
  • cargoCombatAdvanceWeight: 輸送中の戦闘ユニット前進をどれだけ褒めるか。
  • enemyProductionBlockBonus: 敵の生産施設を塞ぐ位置取りのボーナス。
  • nextTurnCaptureThreatWeight: 次ターンに敵へ取られそうな施設価値をどれだけ嫌うか。
施設目標の評価
  • captureObjectiveValueScale: 施設自体の価値をどれだけ強く見るか。
  • captureObjectiveDistancePenalty: 目標施設まで遠いことへの減点。
  • captureObjectiveCongestionWeight: 同じ目標へ味方が集まりすぎることへの減点。
  • captureObjectiveProgressWeight: 施設占領に近づく行動をどれだけ褒めるか。
将来生産と相性
  • futureBuildCostWeight: 将来作れるユニットのコスト価値をどれだけ見るか。
  • futureProductionSavingsWeight: 今使わず貯金する価値をどれだけ見るか。
  • productionMatchupOffenseWeight: 対ユニット相性の攻撃面をどれだけ重視するか。
  • productionMatchupScale: 全体の相性スコアを生産判断へどれだけ反映するか。
  • productionCounterDemandScale: 敵構成への対抗需要をどれだけ大きく見積もるか。
  • productionCounterSurplusTolerance: 対抗ユニットの過剰保有をどこまで許すか。
  • productionCounterSaturationPenaltyScale: 対抗戦力の作りすぎへの減点。
  • productionCounterSameTypePenaltyScale: 同一タイプ作りすぎへの減点。
個別生産ボーナス
  • productionTankBBonus: TankB を作る追加ボーナス。
  • productionArmoredCarBonus: ArmoredCar を作る追加ボーナス。
  • productionTankAHalfFundsPenaltyWeight: 所持金の半分超を TankA に使うときの減点重み。
  • productionNonCaptureHalfFundsPenaltyWeight: 非占領ユニットへ大金を使うときの減点重み。
占領戦力の目標数
  • desiredCapturingUnitsBase: 欲しい占領ユニット数の基本値。
  • desiredCapturingUnitsPerEnemyFacilityDivisor: 敵施設数から必要占領数を増やす比率。
  • desiredCapturingUnitsMin: 必要占領数の下限。
  • desiredCapturingUnitsMax: 必要占領数の上限。
  • openingCapturePhaseTarget: 序盤の占領フェーズとみなす目標数。
占領ユニット生産の圧力
  • productionCaptureNeedBonusBase: 占領役不足時の基礎ボーナス。
  • productionCaptureNeedBonusPerShortfall: 占領役不足 1 体ごとの追加ボーナス。
  • productionCaptureSurplusPenaltyBase: 占領役過多時の基礎減点。
  • productionCaptureSurplusPenaltyPerExtra: 占領役余剰 1 体ごとの追加減点。
  • productionInfantryBaseBonus: 歩兵生産の基本ボーナス。
  • productionInfantryNoInfantryBonus: 歩兵が 0 のとき歩兵を強く作らせるボーナス。
  • productionInfantrySurplusPenalty: 歩兵過多時の減点。
  • productionEngineerSurplusPenalty: 工兵過多時の減点。
どの占領役を優先するか
  • captureUnitOpenTargetWeight: 空いている施設が多いとき占領役を増やす重み。
  • captureUnitCloseRaceWeight: 競争が激しい施設争いで占領役を増やす重み。
  • captureUnitBehindWeight: 施設数で負けているとき占領役を増やす重み。
  • infantryOpenTargetWeight: 上記のうち特に歩兵へ載せる追加重み。
  • infantryCloseRaceWeight: 近い競争時に歩兵を優先する重み。
  • infantryBehindWeight: 劣勢時に歩兵を優先する重み。
  • captureReserveUnits: 必要占領数に上乗せする予備枠。
  • captureSatisfiedPressureScale: 占領不足でないときに占領圧力をどれだけ弱めるか。
貯金判断の緩和
  • captureSavingsOpenTargetReliefWeight: 空き施設が多いとき貯金減点をどれだけ緩めるか。
  • captureSavingsCloseRaceReliefWeight: 競争が近いとき貯金減点をどれだけ緩めるか。
  • captureSavingsBehindReliefWeight: 施設数で負けているとき貯金減点をどれだけ緩めるか。
  • captureSavingsShortfallReliefWeight: 占領役不足時に貯金減点をどれだけ緩めるか。
追撃・位置取り
  • matchupPursuitMaxRelevantDistance: 追撃評価で見る最大距離。
  • matchupPursuitOffenseWeight: 追撃先での攻撃有利をどれだけ重視するか。
  • matchupPursuitDefenseWeight: 追撃先で受ける反撃リスクをどれだけ重視するか。
  • matchupPursuitProgressWeight: 追撃に有利な位置へ移動する価値をどれだけ褒めるか。

SPSAの実装

事前に、ChatGPTでSPSAのアルゴリズムを調査し、疑似コードで実装したものを用意した。
それを入力として、CodexでSPSAを使用してパラメータチューニングを行うコマンドラインツールを実装した。

ゲームボーイウォーズのマップから変換したマップの一覧をランダムで選択して自己対戦を行うようにした。

試したところ、何分経っても1イテレーションが完了しない。
コマメ島のみにしたところ、1イテレーション30秒くらいで完了した。

広いマップでAIの強さがほぼ同じだと、均衡するため、なかなか決着がつかなくなるためと思われる。
終盤も拠点を砲台で固めるなどすると、なかなか決着が付かなくなる。

終盤向けのルールを追加するなどで対策できるかもしれないが、とりあえず狭いマップで調整することにした。

コマメ島でチューニング

まずは、コマメ島のみでチューニングを行った。

Loaded 1 scenarios
Iterations=5 pairs-per=4 max-days=60 max-plies=15360 threads=4 seed=1
[1/5] W/L/D=4/4/0 score=0 time=29.177s (0.486m)
[2/5] W/L/D=2/5/1 score=-3 time=35.721s (0.595m)
[3/5] W/L/D=4/1/3 score=3 time=33.252s (0.554m)
[4/5] W/L/D=3/4/1 score=-1 time=34.340s (0.572m)
[5/5] W/L/D=3/3/2 score=0 time=30.483s (0.508m)
...(略)

初めのイテレーションは、30秒ほどで完了している。

100イテレーションまわしたパラメータでは、2分くらいかかるようになり、Red/Blueを入れ替えて対戦するため、結果は引き分けになっている。

[1/100] W/L/D=4/4/0 score=0 time=130.032s (2.167m)
[2/100] W/L/D=4/4/0 score=0 time=114.390s (1.906m)
[3/100] W/L/D=4/4/0 score=0 time=102.957s (1.716m)
[4/100] W/L/D=4/4/0 score=0 time=96.196s (1.603m)
[5/100] W/L/D=4/4/0 score=0 time=115.316s (1.922m)

テストプレイ

100イテレーションまわしてチューニングしたパラメータで、テストプレイしたところ、装甲車に戦車Bをぶつけてきたり、ロケットランチャーを生産したりと、かなり手ごわくなっていた。


まとめ

AIが弱すぎたので、AIの強化を行った。
ゲームボーイウォーズ系のAIは全探索が困難なため、ルールベース+評価関数+局所探索で実装した。
SPSAでパラメータを自動調整し、手ごわく遊びごたえのあるAIが実装できた。
すべてバイブコーディングで実装しており、自分では1行もコードを書いていない。

AIは改良の余地がまだまだあるが、次はマップの自動生成を実装したい。