Todas as páginas de formatos ↓
Unidades, scripts e configurações

IA: perfis dos adversários controlados pelo computador

Fonte: coreprime/kbot @ 0ab97bf · Editar no GitHub

Os arquivos em ai/*.txt são perfis de adversários do computador em texto simples. Cada perfil declara prioridades de construção e limites de unidades por dificuldade; o motor os lê quando um jogador de IA é configurado num mapa. A chave aiprofile= do OTA escolhe com qual perfil um mapa começa, mas o usuário pode trocá-lo no lobby.

Tip

Experimente você mesmo.

# 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 studio mostra o perfil na aba AI Profile, e o kbot mount o imprime com describe ai/<name>.txt (veja O que o kbot mostra).

Em 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 plans, um por nível de dificuldade. Cada plan 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 Abre um novo bloco de plan. As linhas Weight/Limit que vêm depois só valem quando o plan corresponde à dificuldade da partida, até o próximo plan.
Weight <target> <value> Weight ARMCK 0.5 Multiplica a prioridade de construção do alvo (veja como os pesos se combinam).
Limit <target> <value> Limit ARMSILO 1 Limita quantas unidades do alvo um jogador do computador pode ter: -1 é ilimitado, 0 ou qualquer outro valor negativo proíbe o alvo.

Como o TA 3.1c lê o texto (o formats/ai do kbot-io segue o mesmo comportamento):

  • A linha é dividida em palavras em qualquer espaço em branco (espaços, tabulações, CR, VT, FF), e # encerra a linha onde quer que apareça, mesmo no meio de uma palavra.
  • A primeira palavra é a diretiva, comparada sem diferenciar maiúsculas de minúsculas. Uma linha cuja primeira palavra seja qualquer outra coisa é ignorada; é assim que as linhas // comment da versão comercial são puladas. As palavras depois do valor também são ignoradas, então um // note no fim da linha não faz mal.
  • O 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 é lida como 0, e a diretiva continua valendo: o Limit CORFORT O (com a letra O) do krogoth.txt da versão comercial proíbe o CORFORT, e Limit ARM DECOM 4 limita a categoria ARM inteira a 0.
  • As linhas antes da primeira linha plan são ignoradas quando a partida começa, porque nenhum plan foi selecionado ainda. Elas podem passar a valer se o perfil for recarregado durante a partida. O krogoth.txt da versão comercial começa com duas linhas assim (weight cormakr 0.2, weight armmakr 0.2). Os arquivos de IA do TA: Kingdoms não usam plan de forma alguma; veja TA: Kingdoms: perfis sem plan abaixo.

Níveis de dificuldade

Os perfis originais trazem três plans chamados easy, medium e hard. Um plan vale numa dificuldade quando uma das suas palavras (sem diferenciar maiúsculas de minúsculas) nomeia essa dificuldade (plan medium hard cobre as duas) ou quando a primeira palavra é any. Um plan 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é a próxima linha plan.


Nomes de unidades e palavras de categoria

Tanto Weight quanto Limit podem ter como alvo:

  • O UnitName de uma unidade, por exemplo ARMCOM, CORRAID (comparado sem diferenciar maiúsculas de minúsculas). A diretiva vale só para essa unidade e a trava: as linhas Weight seguintes (no caso de um peso) ou as linhas Limit seguintes (no caso de um limite) não a alteram mais.
  • Uma palavra de categoria (ARM, CORE, PLANT, CONSTR, LEVEL3, SPECIAL, …), comparada com as palavras do campo Category= de cada unidade. Vale para toda unidade correspondente que não esteja travada.
  • ALL: toda unidade que não esteja travada.

Toda unidade começa com prioridade de 100% e sem limite. Um peso multiplica a porcentagem atual, trunca o resultado para um número inteiro e o restringe à faixa de 0 a 100%, então um peso acima de 1 pode recuperar uma unidade reduzida antes, mas nunca a leva além de 100%. Um limite substitui o atual. No plan easy de default.txt, Weight ARM 0.2 deixa toda unidade ARM em 20%; o Weight ARMRAD 0.25 seguinte leva a torre de radar ARM a 5% e a trava; Weight PLANT 2 traz cada fábrica ARM de volta de 20% para 40%.

Important

Os nomes de categoria são comparados com a lista de tokens do Category= da unidade, e não com algum arquivo de taxonomia. Um nome de categoria só "existe" se pelo menos uma unidade o declarar. Escreva LEVL3 errado e a diretiva, sem aviso, não faz nada (os visualizadores do kbot a marcam como matches no unit).


Exemplo comentado: trecho de 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 isso: na dificuldade fácil, toda unidade ARM e CORE cai para 20% de prioridade; as torres de radar caem para 5% e os conversores de metal para 2% (os dois ficam travados em seguida); as fábricas (PLANT) e os construtores (CONSTR) sobem de volta para 40% e 60%, e as linhas próprias dos construtores avançados dobram os seus 60% até o teto de 100% e os travam.


Perfis específicos de mapas

A Cavedog lançou alguns perfis ajustados para certos mapas:

Perfil Usado por
default.txt A maioria dos mapas genéricos
metal.txt Mapas ricos em metal (Metal Heck e afins)
airbattle.txt Mapas focados em combate aéreo
seabattle.txt Mapas focados em combate naval
hover.txt Mapas com muitos hovercrafts
acid.txt Mapas do mundo ácido
urban.txt Mapas urbanos
waterwrld.txt Mapas de mundo aquático
krogoth.txt A missão do chefe Krogoth
missions.txt Missões da campanha

O .ota do mapa escolhe qual usar via aiprofile=, por exemplo aiprofile=metal.


TA: Kingdoms: perfis sem plan

Note

Esta seção trata só do que muda no TA:K. O TAK usa a mesma convenção de nomes de arquivo ai/*.txt e a mesma sintaxe de diretivas weight/limit, mas trata a diretiva plan como opcional.

Todos os perfis de IA do TA: Kingdoms da versão comercial (ai/default.txt, o conjunto ai/mission*.txt da campanha) listam diretivas weight/limit sem nenhuma linha plan: há uma única dificuldade implícita por arquivo. A estrutura é um longo bloco de pesos seguido de um longo bloco de limites, agrupados por lado pelo prefixo do nome da unidade.

Exemplo comentado: as 30 primeiras linhas de 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

Uma leitura dos pesos de default.txt revela as prioridades da Cavedog:

  • aradrag 25: o Dragão de Aramon recebe peso exagerado de propósito; a IA constrói dragões com mais vontade do que qualquer outra coisa.
  • arabuild 10, aracastl 10, arakeep 10, arapries 10: todo tipo de economia/construtor fica com peso 10.
  • arawall 0, arangate 0: zero explícito, nunca construídos.
  • araat 1, arafast 1, arassh 1: unidades básicas que a IA deixa em segundo plano em favor de alternativas de nível mais alto.

O mesmo padrão se repete para as unidades tar*, ver* e zon* mais abaixo no arquivo.

Bloco de limites

Abaixo do 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 uma unidade herói: o peso alto faz com que ela seja construída cedo, e o limite baixo mantém a composição do exército razoável.

Estatísticas dos perfis

O default.txt e os arquivos das missões da campanha seguem todos a mesma forma:

Perfil Linhas de peso Linhas de limite Plans
ai/default.txt 104 104 0
ai/mission06.txt 104 104 0
ai/mission08.txt (missão de Iron Plague) 161 162 0

Os arquivos das missões de Iron Plague têm tabelas de pesos/limites mais ricas porque cobrem as unidades de Creon (prefixo CRE), que o default.txt do jogo base omite.

Como o kbot trata arquivos sem plan

O ai.Parse do kbot-io coloca todas as linhas anteriores à primeira linha plan em AIFile.Preamble, que é o que o TA faz com elas (veja acima); para um perfil do TA: Kingdoms, ai.ParseWith(data, ai.ParseOptions{DefaultPlan: true}) as lê como um único plan implícito que corresponde a todas as dificuldades. Os visualizadores do kbot as mostram numa aba própria, Before first plan, e dizem as duas coisas: o TA as ignora quando a partida começa, e os perfis do TA: Kingdoms, que não têm linhas plan, as aplicam em todas as dificuldades. O kbot não modela como o TA: Kingdoms aplica pesos acima de 1.

O ai.IsAIFile() olha a primeira palavra de cada linha: um arquivo é um perfil quando alguma linha começa com uma diretiva escrita do jeito usual (uma linha plan que nomeia easy, medium, hard ou any, ou uma linha weight/limit cujo valor começa com um número). Isso detecta os perfis do TAK, que não têm plan, e os separados por tabulação, enquanto um .txt que só menciona "weight" ou "limit" no texto não é confundido com um perfil.


Armadilhas

Warning

O jogo não avisa nada. Um nome de unidade escrito errado é lido como uma categoria que não corresponde a nenhuma unidade e não faz nada; um valor que não é número é lido como 0 (e então 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 quebrado costuma ser "a IA está se comportando de um jeito estranho". Os visualizadores do kbot apontam cada um desses casos (veja abaixo).

  • Limit 0, ou qualquer limite negativo diferente de -1, proíbe a IA de construir aquele alvo. -1 remove o teto.
  • # encerra a linha em qualquer posição, mesmo no meio de uma palavra; não existem comentários de bloco. O // só funciona porque uma linha cuja primeira palavra não é uma diretiva é ignorada, e as palavras depois do valor também são ignoradas.
  • Um peso acima de 1 nunca leva uma unidade além de 100%. Ele só pode recuperar uma unidade que um peso de categoria reduziu antes.
  • A primeira linha que nomeia uma unidade a trava. Coloque as linhas específicas de unidades depois das linhas de categoria que elas devem refinar.
  • Os espaços em branco entre os tokens só importam como separadores: tabulações, espaços e espaços múltiplos funcionam do mesmo jeito.
  • Não há suporte a seções aninhadas ou compartilhadas. Cada bloco plan precisa declarar de novo cada peso/limite que lhe interessa.

O que o kbot mostra

O explorador de recursos do studio (aba AI Profile) e o describe do kbot mount leem o perfil do mesmo jeito que o jogo:

  • Before first plan: as linhas do preâmbulo, identificadas como ignoradas quando a partida começa.
  • Uma aba por plan, com cada alvo marcado como unit, category ou all units de acordo com os units/*.fbi da instalação (nome e Category=). Uma categoria que nenhuma unidade tem, que é como um nome de unidade escrito errado é lido, é marcada como matches no unit. Os pesos aparecem como multiplicadores, com uma barra para a porcentagem que sobra para uma unidade que estava em 100%; os limites, como ∞ Unlimited, Disabled (0 ou qualquer valor negativo diferente de -1) ou Max: N.
  • Linhas que o jogo lê de outro jeito: os diagnósticos do kbot-io, como uma palavra de valor que não é número (O é lido como 0) ou palavras depois do valor. Quando a palavra de valor não é o número que o jogo lê, ela aparece ao lado dele (written "O"); outra grafia do mesmo número, como .1 ou 0.10, não aparece.
  • No início da partida (no studio; o kbot mount imprime as contagens): para easy, medium e hard, cada unidade cujo peso ou limite o perfil altera, com 🔒 nos valores que uma linha de unidade travou.

Tamanhos típicos

Métrica Faixa observada nos perfis da Cavedog
Tamanho do arquivo 1–4 KB
Plans por arquivo 3 (easy/medium/hard)
Diretivas de peso por plan 20–80
Diretivas de limite por plan 0–10

Veja também

  • TDF: os metadados de mapa .ota que escolhem um perfil de IA.
  • Glossário: lado, categoria.