IA — perfis dos adversários do computador
Fonte: coreprime/kbot @ 0ab97bf · Editar no GitHub
Os ficheiros
ai/*.txtsão perfis dos adversários do computador, em texto simples. Cada perfil declara, por nível de dificuldade, as prioridades de construção e os limites de unidades; o motor lê-os quando um jogador de IA é configurado para um mapa. A chaveaiprofile=do OTA escolhe o perfil com que um mapa começa, mas o utilizador pode substituí-lo no lobby.
Tip
Experimente por si.
# Plain-text — just read them
ls $(kbot ctx path)/ai/
head -40 $(kbot ctx path)/ai/default.txt
No kbot. O explorador de recursos do estúdio mostra um perfil no
separador AI Profile, e o kbot mount imprime-o com
describe ai/<name>.txt (ver O que o kbot mostra).
A partir de Go. Use o formats/ai do 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
Visão geral
Um perfil é uma sequência de planos, um por nível de dificuldade. Cada
plano contém diretivas Weight e Limit cujo alvo é um único nome de
unidade (ARMCOM), uma palavra de categoria (PLANT, LEVEL3,
SPECIAL) ou 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
...
Diretivas
| Diretiva | Sintaxe | Significado |
|---|---|---|
plan <word>… |
plan easy |
Começa um novo bloco de plano. As linhas Weight/Limit que se seguem só se aplicam quando o plano corresponde à dificuldade do jogo, até ao plan seguinte. |
Weight <target> <value> |
Weight ARMCK 0.5 |
Multiplica a prioridade de construção do alvo (ver como os pesos se combinam). |
Limit <target> <value> |
Limit ARMSILO 1 |
Limita o número de unidades do alvo que um jogador do computador pode ter: -1 é ilimitado, 0 ou qualquer outro valor negativo proíbe-o. |
Como o TA 3.1c lê o texto (o
formats/ai
do kbot-io faz o mesmo):
- Uma linha é dividida em palavras em qualquer espaço em branco —
espaços, tabulações, CR, VT, FF — e
#termina a linha onde quer que apareça, mesmo dentro de uma palavra. - A primeira palavra é a diretiva, comparada sem distinguir
maiúsculas de minúsculas. Uma linha cuja primeira palavra seja outra
coisa é ignorada; é assim que as linhas
// commentdos ficheiros comerciais são saltadas. As palavras depois do valor também são ignoradas, por isso um// noteno fim da linha não faz mal. - Um valor é o prefixo numérico da terceira palavra. Um peso é um
número decimal (
0.5,.5,2,1e1); um limite é um inteiro que dá a volta em 32 bits. Uma palavra de valor que não seja um número lê-se como 0 e a diretiva aplica-se na mesma: oLimit CORFORT O(a letra O) dokrogoth.txtcomercial proíbe o CORFORT, eLimit ARM DECOM 4limita toda a categoria ARM a 0. - As linhas antes da primeira linha
plansão ignoradas quando uma partida começa, porque ainda nenhum plano correspondeu. Podem aplicar-se se o perfil for recarregado durante uma partida. Okrogoth.txtcomercial começa com duas linhas destas (weight cormakr 0.2,weight armmakr 0.2). Os ficheiros de IA do TA: Kingdoms não usamplande todo; veja TA: Kingdoms — perfis sem plan mais abaixo.
Níveis de dificuldade
Os perfis originais trazem três planos chamados easy, medium e
hard. Um plano aplica-se a uma dificuldade quando uma das suas palavras
(sem distinguir maiúsculas de minúsculas) nomeia essa dificuldade
(plan medium hard cobre as duas) ou quando a sua primeira palavra é
any. Um plano cujas palavras não nomeiam nenhuma dificuldade
(plan brutal, um plan sozinho) não corresponde a nada: as linhas
abaixo dele são ignoradas até à linha plan seguinte.
Nomes de unidades e palavras de categoria
Tanto Weight como Limit podem ter como alvo:
- O
UnitNamede uma unidade, por exemploARMCOM,CORRAID(comparado sem distinguir maiúsculas de minúsculas). A diretiva aplica-se só a essa unidade e bloqueia-a: as linhasWeightseguintes (no caso de um peso) ou as linhasLimitseguintes (no caso de um limite) já não a alteram. - Uma palavra de categoria —
ARM,CORE,PLANT,CONSTR,LEVEL3,SPECIAL, … — comparada com as palavras do campoCategory=de cada unidade. Aplica-se a todas as unidades correspondentes que não estejam bloqueadas. ALL: todas as unidades que não estejam bloqueadas.
Todas as unidades começam com 100 % de prioridade e sem limite.
Um peso multiplica a percentagem atual, trunca-a para um número inteiro e
restringe-a ao intervalo 0–100 %, por isso um peso acima de 1 pode
repor uma unidade reduzida antes, mas nunca a leva além de 100 %. Um
limite substitui o atual. No plano easy do default.txt,
Weight ARM 0.2 deixa todas as unidades ARM a 20 %; o
Weight ARMRAD 0.25 que vem depois leva a torre de radar ARM a 5 % e
bloqueia-a; Weight PLANT 2 traz cada fábrica ARM de volta de 20 % para
40 %.
Important
Os aliases de categoria são comparados com a lista de tokens do
Category= da unidade, e não com um ficheiro de taxonomia. Um alias
de categoria só "existe" se pelo menos uma unidade o declarar. Basta
escrever LEVL3 por engano para a diretiva não fazer nada, sem
qualquer aviso (os visualizadores do kbot marcam-na como matches no
unit).
Exemplo comentado — fragmento do 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
Como ler isto: na dificuldade easy, todas as unidades ARM e CORE descem
para 20 % de prioridade; as torres de radar descem para 5 % e os
conversores de metal para 2 % (ficando ambos bloqueados); as fábricas
(PLANT) e os construtores (CONSTR) voltam a subir para 40 % e 60 %, e
as linhas próprias dos construtores avançados duplicam os seus 60 % até
ao teto de 100 % e bloqueiam-nos.
Perfis específicos de mapas
A Cavedog inclui alguns perfis ajustados a determinados mapas:
| Perfil | Usado por |
|---|---|
default.txt |
A maioria dos mapas genéricos |
metal.txt |
Mapas ricos em metal (o Metal Heck e afins) |
airbattle.txt |
Mapas centrados no combate aéreo |
seabattle.txt |
Mapas centrados no combate naval |
hover.txt |
Mapas com muitos hovercrafts |
acid.txt |
Mapas do mundo ácido |
urban.txt |
Mapas urbanos |
waterwrld.txt |
Mapas do mundo aquático |
krogoth.txt |
A missão do Krogoth, o chefe final |
missions.txt |
Missões da campanha |
O .ota do mapa escolhe qual através de aiprofile=, por exemplo
aiprofile=metal.
TA: Kingdoms — perfis sem plan
Note
Esta secção trata só do que muda no TA:K. O TAK usa a mesma
convenção de nomes ai/*.txt e a mesma sintaxe das diretivas
weight/limit, mas trata a diretiva plan como opcional.
Todos os perfis de IA do TA: Kingdoms comercial (ai/default.txt, o
conjunto ai/mission*.txt da campanha) listam diretivas weight/limit
sem nenhuma linha plan: há apenas uma dificuldade implícita por
ficheiro. A estrutura é um longo bloco de pesos seguido de um longo bloco
de limites, agrupados por lado segundo o prefixo do nome da unidade.
Exemplo comentado — as primeiras 30 linhas do 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
Um levantamento do peso dado a cada unidade no default.txt revela as
prioridades da Cavedog:
aradrag 25— o Dragão de Aramon tem um peso propositadamente exagerado; a IA constrói dragões com mais vontade do que qualquer outra coisa.arabuild 10,aracastl 10,arakeep 10,arapries 10— todos os tipos de economia/construtor ficam com peso 10.arawall 0,arangate 0— explicitamente zero, nunca são construídos.araat 1,arafast 1,arassh 1— unidades básicas que a IA deixa para segundo plano, em favor de alternativas de nível superior.
O mesmo padrão repete-se para as unidades tar*, ver* e zon* mais
abaixo no ficheiro.
Bloco de limites
A seguir ao bloco de pesos vem um bloco de limites paralelo:
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
…
Repare na assimetria: aradrag tem peso 25 (prioridade alta) mas
limite 1 (nunca mais de um). É assim que a IA do TA:K constrói em
direção a uma unidade de herói: o peso alto faz com que seja construída
cedo, o limite baixo mantém razoável a composição do exército.
Estatísticas dos perfis
O default.txt e os ficheiros das missões da campanha seguem todos a
mesma forma:
| Perfil | Linhas Weight | Linhas Limit | Planos |
|---|---|---|---|
ai/default.txt |
104 | 104 | 0 |
ai/mission06.txt |
104 | 104 | 0 |
ai/mission08.txt (missão do Iron Plague) |
161 | 162 | 0 |
Os ficheiros das missões do Iron Plague têm tabelas de pesos/limites mais
ricas porque cobrem as unidades Creon (prefixo CRE) que o default.txt
do jogo base omite.
Como o kbot trata os ficheiros sem plan
O ai.Parse do kbot-io põe todas as linhas anteriores à primeira linha
plan em AIFile.Preamble, que é o que o TA faz com elas (ver acima);
para um perfil do TA: Kingdoms,
ai.ParseWith(data, ai.ParseOptions{DefaultPlan: true}) lê-as para um
único plano implícito que corresponde a todas as dificuldades. Os
visualizadores do kbot mostram-nas num separador próprio,
Before first plan, e dizem as duas coisas: o TA ignora-as quando uma
partida começa, e os perfis do TA: Kingdoms, que não têm linhas plan,
aplicam-nas em todas as dificuldades. O kbot não modela a forma como o
TA: Kingdoms aplica pesos acima de 1.
O ai.IsAIFile() olha para a primeira palavra de cada linha: um
ficheiro é um perfil quando alguma linha começa por uma diretiva escrita
da forma habitual (uma linha plan que nomeie easy, medium, hard
ou any, ou uma linha weight/limit cujo valor comece por um número).
Isto deteta os perfis do TAK, que não têm plan, e os que usam
tabulações como separador, sem tomar por perfil um .txt que apenas
mencione "weight" ou "limit" no texto.
Armadilhas
Warning
O jogo não avisa de nada. Um nome de unidade mal escrito é lido
como uma categoria que não corresponde a nenhuma unidade e não faz
nada; um valor que não seja um número lê-se como 0 (e assim um limite
proíbe o alvo); as linhas antes do primeiro plan são ignoradas no
início da partida. O primeiro sinal de um perfil estragado costuma ser
"a IA está a comportar-se de forma estranha". Os visualizadores do
kbot assinalam cada um destes casos (ver abaixo).
Limit 0, ou qualquer limite negativo que não seja-1, impede a IA de construir esse alvo.-1levanta o limite.#termina uma linha em qualquer ponto, mesmo dentro de uma palavra; não há comentários de bloco.//só funciona porque uma linha cuja primeira palavra não é uma diretiva é ignorada e as palavras a seguir ao valor também.- Um peso acima de 1 nunca leva uma unidade além de 100 %. Só pode repor uma unidade que um peso de categoria tenha reduzido antes.
- A primeira linha que nomeia uma unidade bloqueia-a. Coloque as linhas específicas de unidades depois das linhas de categoria que devem afinar.
- O espaço em branco entre tokens só conta como separador: tabulações, espaços simples ou vários espaços funcionam todos da mesma forma.
- Não há suporte para secções aninhadas ou partilhadas. Cada bloco
plantem de voltar a declarar todos os pesos/limites que lhe interessam.
O que o kbot mostra
O explorador de recursos do estúdio (separador AI Profile) e o
describe do kbot mount leem o perfil como o jogo o lê:
- Before first plan: as linhas do preâmbulo, assinaladas como ignoradas quando uma partida começa.
- Um separador por plano, com cada alvo marcado como unit,
category ou all units em relação aos
units/*.fbida instalação (nome eCategory=). Uma categoria que nenhuma unidade tem, que é como se lê um nome de unidade mal escrito, é marcada como matches no unit. Os pesos aparecem como multiplicadores, com uma barra para a percentagem com que fica uma unidade que estava a 100 %; os limites aparecem como ∞ Unlimited, Disabled (0 ou qualquer valor negativo que não seja -1) ou Max: N. - Linhas que o jogo lê de outra forma: os diagnósticos do kbot-io,
como uma palavra de valor que não é um número (
Olê-se como 0) ou palavras depois do valor. Uma palavra de valor que não seja o número que o jogo lê aparece ao lado dele (written "O"); outra grafia do mesmo número, como.1ou0.10, não aparece. - At game start (estúdio; o
kbot mountimprime as contagens): para easy, medium e hard, todas as unidades cujo peso ou limite o perfil altera, com 🔒 nos valores que uma linha de unidade bloqueou.
Tamanhos típicos
| Métrica | Intervalo observado nos perfis da Cavedog |
|---|---|
| Tamanho do ficheiro | 1–4 KB |
| Planos por ficheiro | 3 (easy/medium/hard) |
| Diretivas Weight por plano | 20–80 |
| Diretivas Limit por plano | 0–10 |