IA — Profili degli avversari computer
I file in
ai/*.txtsono profili degli avversari computer in testo semplice. Ogni profilo dichiara, per ciascun livello di difficoltà, le priorità di costruzione e i limiti di unità; il motore li legge quando su una mappa viene configurato un giocatore computer. La chiaveaiprofile=dell'OTA sceglie il profilo con cui parte una data mappa, ma l'utente può cambiarlo nella lobby.
Tip
Provalo tu stesso.
# Plain-text — just read them
ls $(kbot ctx path)/ai/
head -40 $(kbot ctx path)/ai/default.txt
In kbot. L'esploratore di asset dello studio mostra un profilo nella
sua scheda AI Profile, e kbot mount lo stampa con
describe ai/<name>.txt (vedi Che cosa mostra kbot).
Da Go. Usa formats/ai di 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
In breve
Un profilo è una sequenza di plan, uno per livello di difficoltà. Ogni
plan contiene direttive Weight e Limit il cui bersaglio è un singolo
nome di unità (ARMCOM), una parola di categoria (PLANT, LEVEL3,
SPECIAL) oppure 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
...
Direttive
| Direttiva | Sintassi | Significato |
|---|---|---|
plan <word>… |
plan easy |
Apre un nuovo blocco plan. Le righe Weight/Limit che seguono, fino al plan successivo, si applicano solo quando il plan corrisponde alla difficoltà della partita. |
Weight <target> <value> |
Weight ARMCK 0.5 |
Moltiplica la priorità di costruzione del bersaglio (vedi come si combinano i pesi). |
Limit <target> <value> |
Limit ARMSILO 1 |
Limita quanti esemplari del bersaglio può possedere un giocatore computer: -1 significa illimitato, 0 o qualsiasi altro valore negativo lo vieta. |
Come TA 3.1c legge il testo (formats/ai
di kbot-io fa lo stesso):
- Una riga viene divisa in parole su qualsiasi spazio bianco (spazi,
tabulazioni, CR, VT, FF), e
#termina la riga ovunque compaia, anche dentro una parola. - La prima parola è la direttiva, confrontata ignorando maiuscole e
minuscole. Una riga la cui prima parola è qualsiasi altra cosa viene
ignorata: è così che vengono saltate le righe
// commentdei file originali. Anche le parole dopo il valore vengono ignorate, quindi un// notein coda non fa danni. - Un valore è il prefisso numerico della terza parola. Un peso è un
numero decimale (
0.5,.5,2,1e1); un limite è un intero che si riduce a 32 bit. Una parola di valore che non è un numero vale 0, e la direttiva si applica comunque: ilLimit CORFORT O(una lettera O) delkrogoth.txtoriginale vieta CORFORT, eLimit ARM DECOM 4limita a 0 l'intera categoria ARM. - Le righe prima della prima riga
planvengono ignorate all'inizio di una partita, perché nessun plan corrisponde ancora. Possono applicarsi se il profilo viene ricaricato durante una partita. Ilkrogoth.txtoriginale comincia con due righe del genere (weight cormakr 0.2,weight armmakr 0.2). I file IA di TA: Kingdoms non usano affattoplan: vedi TA: Kingdoms — profili senza plan più avanti.
Livelli di difficoltà
I profili standard contengono tre plan chiamati easy, medium e hard.
Un plan si applica a una difficoltà quando una delle sue parole (ignorando
maiuscole e minuscole) nomina quella difficoltà (plan medium hard le copre
entrambe) oppure quando la sua prima parola è any. Un plan le cui parole
non nominano alcuna difficoltà (plan brutal, un plan da solo) non
corrisponde a nulla: le righe che contiene vengono ignorate fino alla riga
plan successiva.
Nomi di unità e parole di categoria
Sia Weight sia Limit possono avere come bersaglio:
- Lo
UnitNamedi un'unità, ad es.ARMCOM,CORRAID(confrontato ignorando maiuscole e minuscole). La direttiva si applica solo a quell'unità e la blocca: le righeWeightsuccessive (per un peso) o le righeLimitsuccessive (per un limite) non la modificano più. - Una parola di categoria (
ARM,CORE,PLANT,CONSTR,LEVEL3,SPECIAL, …), confrontata con le parole del campoCategory=di ogni unità. Si applica a ogni unità corrispondente che non sia bloccata. ALL: ogni unità che non sia bloccata.
Ogni unità parte con priorità 100 % e nessun limite. Un peso
moltiplica la percentuale corrente, la tronca a un numero intero e la
limita all'intervallo 0–100 %, quindi un peso maggiore di 1 può ripristinare
un'unità ridotta in precedenza ma non la porta mai oltre il 100 %. Un limite
sostituisce quello corrente. Nel plan easy di default.txt,
Weight ARM 0.2 lascia ogni unità Arm al 20 %; il successivo
Weight ARMRAD 0.25 porta la torre radar Arm al 5 % e la blocca;
Weight PLANT 2 riporta ogni fabbrica Arm dal 20 % al 40 %.
Important
Gli alias di categoria vengono confrontati con la lista di token
Category= dell'unità, non con un qualche file di tassonomia. Un alias
di categoria "esiste" solo se almeno un'unità lo dichiara. Scrivi LEVL3
e la direttiva non fa nulla, in silenzio (i visualizzatori di kbot la
segnano come matches no unit, "non corrisponde ad alcuna unità").
Esempio svolto — frammento di 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
Come leggerlo: a difficoltà easy ogni unità Arm e Core scende al 20 % di
priorità; le torri radar scendono al 5 % e i metal maker al 2 % (dopodiché
entrambi restano bloccati); le fabbriche (PLANT) e i costruttori
(CONSTR) risalgono al 40 % e al 60 %, e le righe dedicate ai costruttori
avanzati raddoppiano il loro 60 % fino al tetto del 100 % e li bloccano.
Profili specifici per mappa
Cavedog distribuisce una manciata di profili tarati sulle mappe:
| Profilo | Usato da |
|---|---|
default.txt |
La maggior parte delle mappe generiche |
metal.txt |
Mappe ricche di metallo (Metal Heck e simili) |
airbattle.txt |
Mappe incentrate sull'aviazione |
seabattle.txt |
Mappe incentrate sulla marina |
hover.txt |
Mappe con molti hovercraft |
acid.txt |
Mappe del mondo acido |
urban.txt |
Mappe urbane |
waterwrld.txt |
Mappe del mondo acquatico |
krogoth.txt |
La missione del boss Krogoth |
missions.txt |
Missioni della campagna |
Il .ota della mappa sceglie quale usare tramite aiprofile=, ad es.
aiprofile=metal.
TA: Kingdoms — profili senza plan
Note
Questa sezione riguarda solo le differenze di TA:K. TAK usa la stessa
convenzione per i nomi dei file ai/*.txt e la stessa sintassi delle
direttive weight/limit, ma considera facoltativa la direttiva plan.
Ogni profilo IA originale di TA: Kingdoms (ai/default.txt, la serie
ai/mission*.txt della campagna) elenca direttive weight/limit
senza alcuna riga plan: c'è una sola difficoltà implicita per file.
La struttura è un lungo blocco di pesi seguito da un lungo blocco di
limiti, raggruppati per fazione in base al prefisso del nome dell'unità.
Esempio svolto — prime 30 righe di 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
Un'analisi della distribuzione dei pesi in default.txt rivela le priorità
di Cavedog:
aradrag 25: il Drago di Aramon ha volutamente un peso eccessivo; l'IA costruirà draghi con più slancio di qualsiasi altra cosa.arabuild 10,aracastl 10,arakeep 10,arapries 10: ogni tipo legato all'economia o alla costruzione ha peso 10.arawall 0,arangate 0: esplicitamente a zero, mai costruiti.araat 1,arafast 1,arassh 1: unità di base a cui l'IA dà meno priorità, a favore di alternative di livello superiore.
Lo stesso schema si ripete più avanti nel file per le unità tar*, ver*
e zon*.
Blocco dei limiti
Sotto il blocco dei pesi arriva un blocco parallelo di limiti:
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
…
Nota l'asimmetria: aradrag ha peso 25 (priorità alta) ma limite 1
(mai più di uno). È così che l'IA di TA:K punta a un'unità eroe: il peso
alto la fa costruire presto, il limite basso mantiene ragionevole la
composizione dell'esercito.
Statistiche dei profili
default.txt e i file delle missioni della campagna hanno tutti la stessa
forma:
| Profilo | Righe weight | Righe limit | Plan |
|---|---|---|---|
ai/default.txt |
104 | 104 | 0 |
ai/mission06.txt |
104 | 104 | 0 |
ai/mission08.txt (missione di Iron Plague) |
161 | 162 | 0 |
I file delle missioni di Iron Plague hanno tabelle di pesi e limiti più
ricche perché coprono le unità Creon (prefisso CRE) che il default.txt
del gioco base omette.
Come kbot gestisce i file senza plan
ai.Parse di kbot-io mette ogni riga che precede la prima riga plan in
AIFile.Preamble, che è ciò che TA fa con quelle righe (vedi sopra); per
un profilo di TA: Kingdoms, ai.ParseWith(data, ai.ParseOptions{DefaultPlan: true}) le legge in un unico plan implicito che corrisponde a ogni
difficoltà. I visualizzatori di kbot le mostrano in una scheda a parte,
Before first plan, e dicono entrambe le cose: TA le ignora all'inizio di
una partita, mentre i profili di TA: Kingdoms, che non hanno righe plan, le
applicano a ogni difficoltà. kbot non modella il modo in cui TA: Kingdoms
applica i pesi maggiori di 1.
ai.IsAIFile() guarda la prima parola di ogni riga: un file è un
profilo quando una riga comincia con una direttiva scritta nel modo
consueto (una riga plan che nomina easy, medium, hard o any,
oppure una riga weight/limit il cui valore comincia con un numero).
Così riconosce i profili di TAK, che non hanno plan, e quelli separati da
tabulazioni, mentre un .txt che si limita a citare "weight" o "limit" nel
testo non viene scambiato per un profilo.
Insidie
Warning
Il gioco non segnala nulla. Un nome di unità scritto male viene letto
come una categoria che non corrisponde ad alcuna unità e non fa nulla; un
valore che non è un numero vale 0 (quindi un limite vieta il bersaglio);
le righe prima del primo plan vengono ignorate all'inizio della partita.
Il primo segno di un profilo rotto è di solito "l'IA si comporta in modo
strano". I visualizzatori di kbot segnalano ciascuno di questi casi (vedi
più avanti).
Limit 0, o qualsiasi limite negativo diverso da-1, impedisce all'IA di costruire quel bersaglio.-1toglie il tetto.#termina una riga ovunque, anche dentro una parola; non esistono commenti a blocco.//funziona solo perché una riga la cui prima parola non è una direttiva viene ignorata, e le parole in coda dopo il valore vengono ignorate.- Un peso maggiore di 1 non porta mai un'unità oltre il 100 %. Può solo ripristinare un'unità ridotta in precedenza dal peso di una categoria.
- La prima riga che nomina un'unità la blocca. Metti le righe specifiche per le unità dopo le righe di categoria che devono rifinire.
- Lo spazio bianco tra i token conta solo come separatore: tabulazioni, spazi e spazi multipli funzionano allo stesso modo.
- Non ci sono sezioni annidate o condivise. Ogni blocco
plandeve dichiarare di nuovo ogni peso e limite che gli interessa.
Che cosa mostra kbot
L'esploratore di asset dello studio (scheda AI Profile) e il describe
di kbot mount leggono il profilo come fa il gioco:
- Before first plan (prima del primo plan): le righe del preambolo, segnalate come ignorate all'inizio di una partita.
- Una scheda per plan, in cui ogni bersaglio è contrassegnato come
unit, category o all units (unità, categoria o tutte le unità) in
base ai
units/*.fbidell'installazione (nome eCategory=). Una categoria che nessuna unità possiede, ed è così che si presenta un nome di unità scritto male, viene segnata come matches no unit. I pesi sono mostrati come moltiplicatori, con una barra per la percentuale che resta a un'unità partita dal 100 %; i limiti come ∞ Unlimited, Disabled (0 o qualsiasi valore negativo diverso da -1) o Max: N. - Righe che il gioco legge in modo diverso: le diagnostiche di kbot-io,
come una parola di valore che non è un numero (
Ovale 0) o delle parole dopo il valore. Una parola di valore che non corrisponde al numero letto dal gioco viene mostrata accanto a esso (written "O"); un altro modo di scrivere lo stesso numero, come.1o0.10, no. - All'inizio della partita (nello studio;
kbot mountstampa i conteggi): per easy, medium e hard, ogni unità di cui il profilo cambia il peso o il limite, con 🔒 sui valori bloccati da una riga di unità.
Dimensioni tipiche
| Metrica | Intervallo osservato nei profili di Cavedog |
|---|---|
| Dimensione del file | 1–4 KB |
| Plan per file | 3 (easy/medium/hard) |
| Direttive weight per plan | 20–80 |
| Direttive limit per plan | 0–10 |