AI — コンピューター対戦相手のプロファイル
ai/*.txtのファイルは、プレーンテキストで書かれたコンピューター対戦相手のプロファイルです。各プロファイルには難易度ごとの建設優先度とユニット数の上限が記述されており、マップにAIプレイヤーが設定されているとエンジンがこれを読み込みます。マップがどのプロファイルで始まるかはOTAのaiprofile=キーで決まりますが、ユーザーはロビーでこれを変更できます。
Tip
自分で試す
# Plain-text — just read them
ls $(kbot ctx path)/ai/
head -40 $(kbot ctx path)/ai/default.txt
kbotでは、スタジオのアセットエクスプローラーのAI Profileタブにプロファイルが表示されます。kbot mountではdescribe ai/<name>.txtで内容を出力できます(kbotでの表示を参照)。
Goから使う場合は、kbot-ioのformats/aiを使います。
import "github.com/coreprime/kbot-io/formats/ai"
raw, _ := os.ReadFile("ai/default.txt")
profile, _ := ai.Parse(raw)
// profile.Preamble: lines before the first plan; profile.Plans: plan.Name,
// plan.Weights, plan.Limits; profile.Diagnostics: lines read unusually.
settings := ai.NewResolver(units).Apply(profile, ai.Easy) // per-unit result
概要
プロファイルはプランの並びで、プランは難易度ごとに1つずつあります。各プランにはWeightディレクティブとLimitディレクティブが並び、その対象は単一のユニット名(ARMCOM)、カテゴリ語(PLANT、LEVEL3、SPECIAL)、またはALLのいずれかです。
plan easy
Weight ARM 0.2
Weight CORE 0.2
Weight PLANT 2
Weight CONSTR 3
Weight ARMACK 2
Weight CORACK 2
Limit ARMSILO 1
Limit CORSILO 1
plan medium
Weight ARM 1.0
Weight CORE 1.0
...
ディレクティブ
| ディレクティブ | 構文 | 意味 |
|---|---|---|
plan <word>… |
plan easy |
新しいプランのブロックを開始します。続くWeight/Limit行は、次のplanまでの間、そのプランがゲームの難易度に一致する場合にだけ適用されます。 |
Weight <target> <value> |
Weight ARMCK 0.5 |
対象の建設優先度に値を掛けます(重みの組み合わせ方を参照)。 |
Limit <target> <value> |
Limit ARMSILO 1 |
コンピュータープレイヤーが保有できる対象の数に上限を設けます。-1は無制限で、0またはその他の負の値はその対象を禁止します。 |
TA 3.1cはテキストを次のように読みます(kbot-ioのformats/aiもこれに従っています)。
- 行は任意の空白文字で単語に分割されます(スペース、タブ、CR、VT、FF)。また、
#は出現した場所で行を終わらせます。単語の途中にあっても同じです。 - 最初の単語がディレクティブです。大文字と小文字は区別せずに比較されます。最初の単語がそれ以外の行は無視されます。製品版の
// comment行が読み飛ばされるのはこのためです。値の後ろの単語も無視されるので、行末に// noteを付けても問題ありません。 - 値は3番目の単語の先頭にある数値部分です。重みは10進数(
0.5、.5、2、1e1)で、上限は32ビットで折り返す整数です。数値でない値の単語は0として読まれ、ディレクティブはそのまま適用されます。製品版のkrogoth.txtにあるLimit CORFORT O(英字のO)はCORFORTを禁止し、Limit ARM DECOM 4はARMカテゴリ全体の上限を0にします。 - 最初の
plan行より前の行は、ゲーム開始時には無視されます。まだどのプランも一致していないためです。ゲーム中にプロファイルが再読み込みされた場合は、適用されることがあります。製品版のkrogoth.txtは、このような行2つ(weight cormakr 0.2、weight armmakr 0.2)で始まっています。TA: KingdomsのAIファイルはplanをまったく使いません。後述のTA: Kingdoms — planのないプロファイルを参照してください。
難易度
標準のプロファイルにはeasy、medium、hardという名前の3つのプランがあります。プランは、その単語のいずれか(大文字と小文字は区別しません)が難易度を指している場合(plan medium hardなら両方が対象)、または最初の単語がanyの場合に、その難易度で適用されます。どの難易度も指さない単語しかないプラン(plan brutal、単独のplan)は何にも一致せず、その下の行は次のplan行まで無視されます。
ユニット名とカテゴリ語
WeightとLimitは、どちらも次のものを対象にできます。
- ユニットの
UnitName:たとえばARMCOM、CORRAID(大文字と小文字は区別せずに比較)。ディレクティブはそのユニットだけに適用され、そのユニットをロックします。以降のWeight行(重みの場合)やLimit行(上限の場合)では、もう変更されません。 - カテゴリ語:
ARM、CORE、PLANT、CONSTR、LEVEL3、SPECIALなど。各ユニットのCategory=フィールドの単語と照合され、一致するユニットのうち、ロックされていないものすべてに適用されます。 ALL:ロックされていないすべてのユニット。
すべてのユニットは、優先度100 %、上限なしの状態から始まります。重みは現在のパーセンテージに掛けられ、整数に切り捨てられたうえで0〜100 %の範囲に制限されます。そのため、1より大きい重みは以前に下げられたユニットを元に戻すことはできても、100 %を超えて引き上げることはありません。上限は現在の上限を置き換えます。default.txtのeasyプランでは、Weight ARM 0.2でARMの全ユニットが20 %になり、その後のWeight ARMRAD 0.25でARMのレーダー塔が5 %になってロックされ、Weight PLANT 2でARMの各工場が20 %から40 %に戻ります。
Important
カテゴリの別名は、ユニットのCategory=のトークンリストと照合されます。分類用のファイルと照合されるわけではありません。カテゴリの別名が「存在する」のは、少なくとも1つのユニットがそれを宣言している場合だけです。LEVL3と綴りを間違えると、ディレクティブは何も知らせずに、何の効果も持ちません(kbotのビューアーではmatches no unit、つまりどのユニットにも一致しないと表示されます)。
実例 — default.txtの一部
// DEFAULT PROFILE
//--------------------------- EASY
plan easy
Weight ARM 0.2 // Every Arm unit to 20%
Weight CORE 0.2
Weight ARMRAD 0.25 // Radar towers to 5%, locked
Weight CORRAD 0.25
Weight ARMMAKR .1 // …metal makers to 2%, locked
Weight CORMAKR .1
Weight PLANT 2 // Factories back up to 40%
Weight CONSTR 3 // Constructors to 60%
// encourages advanced units
Weight ARMACK 2 // Advanced Construction Kbots
Weight CORACK 2
Weight ARMACV 2
Weight CORACV 2
Weight ARMACA 2
Weight CORACA 2
Weight SPECIAL 2
Weight LEVEL3 2
この部分は次のように読めます。easyの難易度では、ARMとCOREの全ユニットの優先度が20 %に下がります。レーダー塔は5 %、金属変換機は2 %まで下がり(どちらもその後ロック)、工場(PLANT)と建設ユニット(CONSTR)はそれぞれ40 %と60 %まで戻ります。上級建設ユニットは専用の行で60 %が2倍になって上限の100 %に収まり、ロックされます。
マップ専用のプロファイル
Cavedogは、マップに合わせて調整したプロファイルをいくつか同梱しています。
| プロファイル | 使われる場面 |
|---|---|
default.txt |
ほとんどの汎用マップ |
metal.txt |
金属が豊富なマップ(Metal Heckなど) |
airbattle.txt |
航空戦が中心のマップ |
seabattle.txt |
海戦が中心のマップ |
hover.txt |
ホバークラフトが主役のマップ |
acid.txt |
酸の惑星のマップ |
urban.txt |
都市のマップ |
waterwrld.txt |
水の惑星のマップ |
krogoth.txt |
クロゴスと戦うボスミッション |
missions.txt |
キャンペーンのミッション |
どれを使うかは、マップの.otaがaiprofile=で選びます(例:aiprofile=metal)。
TA: Kingdoms — planのないプロファイル
Note
この節はTA:Kだけの差分です。TAKもai/*.txtという同じファイル名の規則と、同じweight/limitディレクティブの構文を使いますが、planディレクティブは省略可能なものとして扱います。
製品版のTA: KingdomsのAIプロファイル(ai/default.txt、キャンペーンのai/mission*.txt一式)はどれも、plan行をまったく使わずにweight/limitディレクティブを並べています。1つのファイルに暗黙の難易度が1つあるだけです。構造は、長い重みのブロックの後に長い上限のブロックが続くもので、どちらもユニット名の接頭辞によって陣営ごとにまとめられています。
実例 — ai/default.txtの最初の30行
// Kingdoms Default AI Profile 3-28-99
weight araarch 5
weight araat 1
weight arabow 8
weight arabroad 5
weight arabuild 10
weight aracan 4
weight aracastl 10
weight araclay 5
weight aradrag 25 // Dragons: top priority
weight arafast 1
weight arakeep 10
weight araknigh 5
weight aralode 10
weight aramana 5
weight arangate 0 // 0 = never build
weight arapal 8
weight arapries 10
weight arapult 1
weight arasmith 8
weight araspy 4
weight arassh 1
weight arasword 5
weight aratre 1
weight arawall 0
weight arawar 1
default.txtの重みの偏りを調べると、Cavedogの優先順位が見えてきます。
aradrag 25:Aramonのドラゴンは意図的に重みを大きくしてあり、AIはほかの何よりも積極的にドラゴンを建設します。arabuild 10、aracastl 10、arakeep 10、arapries 10:経済系・建設系のタイプはどれも重み10です。arawall 0、arangate 0:明示的に0で、建設されることはありません。araat 1、arafast 1、arassh 1:AIがより上位のユニットを優先して後回しにする基本ユニットです。
ファイルのさらに下では、tar*、ver*、zon*のユニットについても同じパターンが繰り返されます。
上限のブロック
重みのブロックの下には、対になる上限のブロックが続きます。
limit araarch 16
limit araat 8
limit arabow 16
limit arabroad 16
limit arabuild 10
limit aracan 3
limit aracastl 2 // Only 2 castles per game
limit araclay 3
limit aradrag 1 // ONE dragon, even though weight=25
limit arafast 4
limit arakeep 2
limit araknigh 16
…
非対称になっている点に注目してください。aradragの重みは25(高い優先度)ですが、上限は1(1体を超えることはない)です。TA:KのAIは、このようにしてヒーローユニットに向けて建設を進めます。高い重みで早い段階に建設させ、低い上限で軍の構成を妥当な範囲に保つわけです。
プロファイルの統計
default.txtとキャンペーンのミッションファイルは、どれも同じ形をしています。
| プロファイル | Weight行 | Limit行 | プラン |
|---|---|---|---|
ai/default.txt |
104 | 104 | 0 |
ai/mission06.txt |
104 | 104 | 0 |
ai/mission08.txt(Iron Plagueのミッション) |
161 | 162 | 0 |
Iron Plagueのミッションファイルの重みと上限の表がより充実しているのは、ベースゲームのdefault.txtにはないCreon(接頭辞CRE)のユニットを扱っているためです。
kbotによるplanのないファイルの扱い
kbot-ioのai.Parseは、最初のplan行より前の行をすべてAIFile.Preambleに入れます。これはTAがそれらの行を扱う方法と同じです(前述)。TA: Kingdomsのプロファイルでは、ai.ParseWith(data, ai.ParseOptions{DefaultPlan: true})でそれらの行を、すべての難易度に一致する暗黙のプラン1つとして読み込みます。kbotのビューアーはそれらの行を専用のBefore first planタブに表示し、2つのことを併記します。TAはゲーム開始時にそれらを無視すること、そしてplan行を持たないTA: Kingdomsのプロファイルは、すべての難易度でそれらを適用することです。kbotは、TA: Kingdomsが1より大きい重みをどう適用するかはモデル化していません。
ai.IsAIFile()は各行の最初の単語を見ます。いずれかの行が通常の書き方のディレクティブ(easy、medium、hard、anyのいずれかを指定したplan行、または値が数字で始まるweight/limit行)で始まっていれば、そのファイルはプロファイルとみなされます。これにより、planを持たないTAKのプロファイルやタブ区切りのプロファイルも検出でき、一方で文章中に「weight」や「limit」が出てくるだけの.txtをプロファイルと取り違えることはありません。
注意点
Warning
ゲームは何も報告しません。綴りを間違えたユニット名は、どのユニットにも一致しないカテゴリとして読まれ、何の効果もありません。数値でない値は0として読まれます(そのため上限なら対象を禁止します)。最初のplanより前の行は、ゲーム開始時に無視されます。プロファイルが壊れていることに最初に気づくのは、たいてい「AIの動きがおかしい」と感じたときです。kbotのビューアーは、これらをそれぞれ指摘します(後述)。
Limit 0、または-1以外の負の上限は、AIがその対象を建設することを禁止します。-1は上限を解除します。#はどこにあっても行を終わらせます。単語の途中でも同じです。ブロックコメントはありません。//が機能するのは、最初の単語がディレクティブでない行が無視され、値の後ろの単語も無視されるからにすぎません。- 1より大きい重みでも、ユニットが100 %を超えることはありません。カテゴリの重みで以前に下げられたユニットを元に戻せるだけです。
- ユニットを指定した最初の行が、そのユニットをロックします。ユニット個別の行は、それが細かく調整するカテゴリの行の後に置いてください。
- トークン間の空白は、区切りとしてだけ意味を持ちます。タブ、スペース、連続したスペースのどれも同じように機能します。
- 入れ子のセクションや共有のセクションはサポートされていません。各
planブロックで、必要な重みと上限をすべて宣言し直す必要があります。
kbotでの表示
スタジオのアセットエクスプローラー(AI Profileタブ)とkbot mountのdescribeは、ゲームと同じ方法でプロファイルを読みます。
- Before first plan:プリアンブル(最初のプランより前)の行です。ゲーム開始時に無視されることが示されます。
- プランごとに1つのタブ:各対象には、インストール先の
units/*.fbi(名前とCategory=)と照らし合わせて、unit、category、all unitsのいずれかの印が付きます。どのユニットも持たないカテゴリ(綴りを間違えたユニット名はこう読まれます)には、matches no unitと表示されます。重みは倍率として表示され、100 %のユニットに残るパーセンテージを示すバーが付きます。上限は、∞ Unlimited、Disabled(0、または-1以外の負の値)、Max: Nのいずれかで表示されます。 - Lines the game reads differently(ゲームが異なる読み方をする行):kbot-ioの診断情報です。たとえば数値でない値の単語(
Oは0として読まれる)や、値の後ろの単語などです。値の単語がゲームの読む数値と異なる場合は、その横に(written "O")と表示されます。.1や0.10のような、同じ数値の別の書き方は表示されません。 - At game start(ゲーム開始時。スタジオで表示され、
kbot mountは件数を出力します):easy、medium、hardのそれぞれについて、プロファイルが重みまたは上限を変更するすべてのユニットを示します。ユニットの行でロックされた値には🔒が付きます。
典型的なサイズ
| 指標 | Cavedogのプロファイルで見られる範囲 |
|---|---|
| ファイルサイズ | 1–4 KB |
| ファイルあたりのプラン数 | 3(easy/medium/hard) |
| プランあたりのWeightディレクティブ数 | 20–80 |
| プランあたりのLimitディレクティブ数 | 0–10 |