Усі сторінки форматів ↓
Юніти, скрипти, конфігурації

ШІ — профілі комп'ютерних суперників

Джерело: 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 до 0.
  • Рядки перед першим рядком 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 позначають її як 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

Як це читати: на легкому рівні складності кожен юніт 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 Місія з босом Krogoth
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 Dragon навмисно має завищену вагу; ШІ будуватиме драконів охочіше, ніж будь-що інше.
  • 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, застосовують їх на кожному рівні складності. kbot не моделює, як TA: Kingdoms застосовує ваги понад 1.

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

Див. також

  • TDF — метадані мапи .ota, які обирають профіль ШІ.
  • Глосарій — side, category.