引き続き、AIに関する理屈をおさえながら、じわじわとAIコモンを作り進めていきましょう。
移動力が1しかないユニットであっても、どこに移動するべきか考えると周囲4マス+初期位置(動かない)で候補は5通り(マス)になります。
AIはこの5択にどうやって答えるのか。というよりも、この5択のなかでもっともお得な選択肢をどう見つけるのか。
その答えが「評価値」です。
「評価値」の概念
どっちが正解?
201の赤いスライムが動こうとしています。
AI設定が「攻撃する」かつ「目的地が自軍リーダー101(左下の青い人)がいる場所」のとき、「左(緑のマル)」と「下(紫のマル)」のどちらを選ぶでしょうか。
解答
移動できるだけ101の座標に近づこうとしていますから、目的地への接近具合はどちらの選択もあまり違いがありません。
だったら、青い夕一(ニワトリ)に”ついで”で攻撃できるほうがお得な選択ではないでしょうか。
つまり答えは左(緑のマル)です。
ざっくり言えば、人間が半ば無意識に行っているこうした判断を、プログラミング的に表したものが「評価値」です。どちらの選択がよりお得か数値化したもの……要は得点です。
左(緑のマル)ルートの評価値(得点)
- 移動できるだけ目的地(101)に近づいた +1点
- 青い夕一に攻撃できる +1点
合計2点
下(紫のマル)ルートの評価値(得点)
- 移動できるだけ目的地(101)に近づいた +1点
- 青い夕一に攻撃できない +0点
合計1点
このようにルートの得点を計算(評価)したら、単純な数字(得点)の比較だけで「総合的にはどのルート選択がお得なのか」が判断できるのです。
評価する項目が多ければ多いほど、賢くて計算時間(処理負荷)の高いAIということになりますね。
というわけで、AIの処理で行う内容は、「そのユニットが1度の移動で行けるマス(ルート)をすべて評価し、もっとも評価値の高いものを選ぶこと」だと言えます。
ただし「山などに引っかからず、ある程度は迂回して進んでほしい」ので、そのためにAI計算での移動力は「基本移動力×2~3」とするのがよいわけです。
しかし、SRPGでは「釣り出して反撃で倒す」がよくあるテクニック。敵AIはそこまで賢くなくてよさそうです。
数ターンぶんの移動力で考える
「┣■移動力計算」コモンの改修
入力値に「モード」を足しましょう。「1:通常」、「2:AI用」です。
そして《計算用の基礎移動力=射程+移動力》としていたものを、《計算用の基礎移動力=射程+移動力×モード》に直します。
通常モードは1なので修正前と変わらない結果になりますが、AI用のモード2では移動力が2倍になりますね。
もちろん、AIコモンからの呼び出し時のみモード2を使用します。
これが「AIは数ターン分の移動力で考える」ということです。
1回(ターン)分の移動力で行ける範囲だけを評価する
AIモードでも「残移動力が入っているマス=行けるマス」と考えてしまうと、移動力3のユニットが5歩も6歩も遠くへ進んでしまいます。
「自分の初期位置からの距離」が「自分の1回分の移動力以下のマス」だけを計算するように、範囲を絞る必要がありますね。
攻撃範囲のみを表示する際に作った「┃┣指定位置からnマス距離にパネル」コモンと、途中まではほぼ同じ動きをします。
「■AI処理」コモン
このコモンで「┣■移動力計算」を最初に済ませてしまうことにしました。ここでCDBのX,Yを先に取得していますので、「┗指示リストの実行」呼び出し時にそのまま入力(受け渡し)して無駄を省きましょう。
「┣移動可範囲のチェック」コモン
「1回ぶんの移動で行ける範囲だけの評価する処理」の本体です(あとでまた処理を足します)。
こんな感じ。
もとの移動力が1だとすると、AI用計算では移動力が2あるものとして計算されますが、移動可範囲コモンは「初期位置からの距離が1以下のマス」つまり「周囲4マス+初期位置」の5マスだけを評価します。
対象となるすべてのマス(とそこで出来る行動=「ルート」)を評価して、もっとも評価値の大きかったルートを採用して「┗指示リストの実行」コモンへ受け渡しましょう。
というわけで、「┣対象マスの評価」というコモンを呼び出し、その返り値で評価値の大小を比較するように手直しします。
対象マスの発見時と、ループの前後に数行の追加が入りました。
- 移動力計算の結果、残移動力が射程以上のマスであること
- 自分以外のユニット番号が登録されていないマスであること
これ以降もまだまだ手直しするコモンなので、とりあえずこのまま話を進めます。
評価のフロー(「┣対象マスの評価」コモンで行うこと)
素直に考えた評価の流れ
実際の組み立ては次回として、ここではどんな流れで処理をすることになるのか、考えていきましょう。
ぱっと思いつくのはこんな流れでしょうか。
- 対象ユニットのAI設定(攻撃するかどうか、目的地はどこか)をCDB・UDBから読み込む
- チェック先の座標と目的地の距離をチェック。ジャストに近いほど評価を小プラス。目的地ジャストなら評価を大プラス
- 攻撃など、なんらかの行動がとれるなら評価を大プラス(攻撃の場合、そのマスから射程分だけ周囲をチェックして他軍ユニットを探す)
- その行動で発生する数値が大きいほどさらに評価を小プラス(攻撃なら相手の残HPをより小さくできる方が高評価)
最初の方の処理は呼び出し元(「┣移動可範囲のチェック」コモン)で済ませて、下位コモンへ入力する方が、無駄がなさそうですね。
しかし、これには問題があります。めちゃくちゃ重いのです。
なにが問題なのか
フローというより、攻撃対象の探し方が問題です。
移動できるマスのすべてで「そのマスから攻撃できるユニットがいるかどうか」を毎回判定すると、死ぬほどの処理負荷になってしまいます。
移動力1のユニットでは、移動先が5マスあるというお話をしました。
射程も1あったとすると、移動先5マスすべてに対して「その周囲4マスの射程内の他軍チェック」が発生します。移動力1、射程1というユニットでさえ、5×4で20マスぶんものチェックが必要なのです。
まともな性能のユニットだとすれば「移動力5、射程2」なんかになりまして、もうすでにどれだけのマスのチェックが必要になるのか把握できません。
というわけで……
あらかじめ「AIで動かすユニットの1回ぶん移動力+射程の距離内にいる他軍ユニットの番号と座標のリスト」をチェックしておくとよいでしょう。
すべてのマスでいるかもわからない他軍ユニットを毎回さがすよりは、事前にチェックしておいた攻撃可能なユニットとの距離が射程と一致しているかを見る方が無駄がないはずです。
事前に攻撃可能ユニットを探すコモン
「┣移動可範囲のチェック」コモンの先頭あたりにでも、次のようなコモンを作って呼び出すようにしましょう。
★「┣攻撃可ユニットリストの取得」コモン
途中までは「┣移動可範囲のチェック」コモンに似ていますね。
何十回と回数ループをまわすようなコモンでは、もうとりあえず「┣50万エラー対策」コモンも挟んでおくと安心です。
それでは次の記事から、実際に評価値を決定するパートを作っていきましょう。