ИИ — профили компьютерного противника
Источник: coreprime/kbot @ 0ab97bf · Редактировать на GitHub
Файлы
ai/*.txt— это текстовые профили компьютерного противника. Каждый профиль задаёт приоритеты строительства и лимиты юнитов для каждого уровня сложности; движок читает их, когда на карте настроен игрок под управлением ИИ. Ключaiprofile=в OTA выбирает, с каким профилем начинается конкретная карта, но в лобби игрок может его переопределить.
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. Используйте formats/ai из kbot-io:
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
Кратко
Профиль — это последовательность планов, по одному на уровень
сложности. Каждый план содержит директивы 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 читает текст (так же поступает
formats/ai
из kbot-io):
- Строка делится на слова по любым пробельным символам — пробелам,
табуляциям, CR, VT, FF, — а
#заканчивает строку в любом месте, даже внутри слова. - Первое слово — директива, сравнивается без учёта регистра. Строка,
первое слово которой — что-то другое, игнорируется; именно так
пропускаются строки
// commentв оригинальных файлах. Слова после значения тоже игнорируются, так что// noteв конце строки ничему не мешает. - Значение — это числовое начало третьего слова. Вес — десятичное
число (
0.5,.5,2,1e1); лимит — целое, которое переполняется по модулю 32 бит. Слово значения, которое не является числом, читается как 0, и директива всё равно применяется:Limit CORFORT O(буква O) в оригинальномkrogoth.txtзапрещает CORFORT, аLimit ARM DECOM 4ограничивает всю категорию ARM нулём. - Строки до первой строки
planпри запуске игры игнорируются, потому что ни один план ещё не подошёл. Они могут подействовать, если профиль перезагружается во время игры. Оригинальныйkrogoth.txtначинается с двух таких строк (weight cormakr 0.2,weight armmakr 0.2). Файлы ИИ TA: Kingdoms вообще не используютplan— см. ниже TA: Kingdoms — профили без plan.
Уровни сложности
Стандартные профили поставляются с тремя планами: easy, medium и
hard. План действует на уровне сложности, если одно из его слов (без
учёта регистра) называет этот уровень — 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 %. Лимит
заменяет текущий. В плане easy из default.txt строка Weight ARM 0.2
оставляет каждому юниту ARM 20 %; следующая Weight ARMRAD 0.25 снижает
радарную вышку ARM до 5 % и закрепляет её; Weight PLANT 2 возвращает
каждый завод ARM с 20 % на 40 %.
Important
Псевдонимы категорий сопоставляются со списком токенов Category=
юнита, а не с каким-либо файлом классификации. Псевдоним категории
«существует», только если его объявляет хотя бы один юнит. Ошибитесь
в написании LEVL3 — и директива молча ничего не сделает (просмотрщики
kbot помечают её как не подходит ни одному юниту).
Разбор примера — фрагмент 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
Как это читать: на лёгкой сложности приоритет каждого юнита ARM и CORE
падает до 20 %; радарные вышки опускаются до 5 %, а синтезаторы металла —
до 2 % (и те и другие затем закреплены); заводы (PLANT) и строители
(CONSTR) поднимаются обратно до 40 % и 60 %, а собственные строки
улучшенных строителей удваивают их 60 % до потолка в 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/default.txt, набор
ai/mission*.txt кампании) перечисляют директивы weight/limit
вообще без строк plan — на файл приходится один неявный уровень
сложности. Структура такая: длинный блок весов, за ним длинный блок
лимитов, сгруппированные по сторонам через префикс имени юнита.
Разбор примера — первые 30 строк ai/default.txt
// 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 намеренно перевешен: ИИ строит драконов охотнее, чем что-либо другое.arabuild 10,aracastl 10,arakeep 10,arapries 10— у всех экономических и строительных типов вес 10.arawall 0,arangate 0— явный ноль, никогда не строятся.araat 1,arafast 1,arassh 1— базовые юниты, которые ИИ отодвигает в пользу альтернатив более высокого уровня.
Та же картина повторяется для юнитов 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 (не больше одного). Так ИИ TA:K строит
героя: высокий вес заставляет построить его рано, а низкий лимит держит
состав армии в разумных рамках.
Статистика профилей
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 таблицы весов и лимитов богаче, потому что
они охватывают юниты Creon (префикс CRE), которых нет в default.txt
основной игры.
Как kbot обрабатывает файлы без plan
ai.Parse из kbot-io помещает все строки до первой строки plan в
AIFile.Preamble — так же с ними поступает TA (см. выше); для профиля
TA: Kingdoms ai.ParseWith(data, ai.ParseOptions{DefaultPlan: true}) читает их в один неявный план, который подходит к любой
сложности. Просмотрщики kbot показывают эти строки на отдельной вкладке
Before first plan и сообщают обе вещи: TA игнорирует их при запуске
игры, а профили TA: Kingdoms, в которых нет строк plan, применяют их на
любой сложности. Как TA: Kingdoms применяет веса больше 1, kbot не
моделирует.
ai.IsAIFile() смотрит на первое слово каждой строки: файл считается
профилем, если какая-нибудь строка начинается с директивы, записанной
обычным образом (строка plan, называющая easy, medium, hard или
any, либо строка weight/limit, значение которой начинается с
числа). Так распознаются профили TAK, в которых нет plan, и профили с
разделением табуляциями, а .txt, где «weight» или «limit» просто
упоминаются в тексте, за профиль не принимается.
Подводные камни
Warning
Игра ни о чём не сообщает. Имя юнита с опечаткой читается как
категория, которая не подходит ни одному юниту, и ничего не делает;
значение, не являющееся числом, читается как 0 (так что лимит
запрещает цель); строки до первого plan при запуске игры
игнорируются. Первый признак сломанного профиля обычно звучит как
«ИИ ведёт себя странно». Просмотрщики kbot отмечают каждый из этих
случаев (см. ниже).
Limit 0или любой отрицательный лимит, кроме-1, запрещает ИИ строить эту цель.-1снимает ограничение.#заканчивает строку где угодно, даже внутри слова; блочных комментариев нет.//работает лишь потому, что строка, первое слово которой не директива, игнорируется, а слова после значения тоже игнорируются.- Вес больше 1 никогда не поднимает юнит выше 100 %. Он может только вернуть юнит, который раньше понизил вес категории.
- Первая строка, называющая юнит, закрепляет его. Ставьте строки для конкретных юнитов после строк категорий, которые они должны уточнять.
- Пробельные символы между токенами значимы только как разделители — табуляции, пробелы и несколько пробелов подряд работают одинаково.
- Вложенных или общих секций нет. Каждый блок
planдолжен заново объявить все нужные ему веса и лимиты.
Что показывает kbot
Обозреватель ресурсов студии (вкладка AI Profile) и describe в
kbot mount читают профиль так же, как игра:
- Before first plan — строки преамбулы с пометкой, что при запуске игры они игнорируются.
- По вкладке на каждый план, где каждая цель помечена как unit,
category или all units по
units/*.fbiустановки (имя иCategory=). Категория, которой нет ни у одного юнита, — а именно так читается имя юнита с опечаткой, — помечается как matches no unit. Веса показаны как множители с полосой процента, который остаётся у юнита со 100 %; лимиты — как ∞ Unlimited, Disabled (0 или любое отрицательное значение, кроме -1) или Max: N. - Строки, которые игра читает иначе, — диагностика kbot-io,
например слово значения, которое не является числом (
Oчитается как 0), или слова после значения. Если слово значения отличается от числа, которое читает игра, оно показано рядом (written "O"); другая запись того же числа, например.1или0.10, не показывается. - At game start (в студии;
kbot mountвыводит количества) — для easy, medium и hard каждый юнит, вес или лимит которого меняет профиль, с 🔒 у значений, закреплённых строкой юнита.
Типичные размеры
| Показатель | Диапазон в профилях Cavedog |
|---|---|
| Размер файла | 1–4 КБ |
| Планов в файле | 3 (easy/medium/hard) |
| Директив weight в плане | 20–80 |
| Директив limit в плане | 0–10 |