Per applicare con successo min / max a un gioco di strategia a turni, devi applicare correttamente tutte le tecniche di scacchi disponibili ...
Funzione di valutazione
Anche i motori di scacchi hanno una forza pessima, se le tue funzioni di valutazione sono cattive. La versione più semplice di una funzione di valutazione è: 1 = partita vinta dal bianco, -1 = partita vinta dal nero, 0 = tutti gli altri casi; Ma questo ti darebbe una performance pessima. Lo stesso accade al tuo gioco a turni! Se vuoi usare min / max (con potatura alfa / beta e roba simile) come negli scacchi, devi anche implementare una ragionevole funzione di valutazione! Altrimenti, non è possibile confrontare le prestazioni di tali algoritmi quando viene applicato al gioco di strategia con il caso in cui viene applicato agli scacchi.
Ciò che fanno le funzioni di valutazione dei motori di scacchi è valutare cose come:
- Quanto è buona la posizione di un pezzo sulla scacchiera?
- Quante volte viene attaccato un pezzo?
- Quante volte il pezzo è protetto?
- In che misura ogni pezzo può "muoversi" liberamente sulla scacchiera? (oppure: quante tessere "controlla")
Le parti della funzione di valutazione devono prima essere "tradotte" nel tuo gioco:
- Posizione del pezzo: è ad esempio su una collina che sta estendendo il suo campo di tiro?
- Attaccato: quanto è in pericolo ogni pezzo? (es. somma dei valori di attacco di unità in grado di attaccare un'unità speciale moltiplicata per una certa probabilità di essere attaccata da essa; la probabilità aumenta, se l'unità è già danneggiata; diminuisce se molte altre unità si trovano nel raggio di azione dell'unità attaccante)
- Proprio attacco: quante unità possono essere attaccate da questo ogni unità?
- Protezione: quanti pezzi ci sono accanto (per aiutare)? Forse un'unità non può attaccare le unità a una distanza minima ed è preferibile proteggerla dall'unità che ha la possibilità di attaccare le unità vicine.
- Mobilità: quanto è mobile la tua unità? (può fuggire?)
Le diverse classificazioni devono essere riassunte in base alla funzione di ponderazione (fattore_a * valutazione_a + fattore_b * ranting_b + ...) per tutte le unità ...
Nei giochi di strategia anche le risorse (oro, legno, ...) rimaste devono essere prese in considerazione.
Se la tua funzione di valutazione è abbastanza buona, nella maggior parte dei casi non è necessario cercare "in profondità" nella struttura. Quindi probabilmente dovrai solo dare un'occhiata più da vicino alle 3 o 10 scelte più promettenti. Vedi il prossimo capitolo ...
Mosse possibili in ogni posizione
La cosa più problematica nell'uso di min / max per i giochi di strategia è che puoi comandare più unità in un turno, mentre negli scacchi ti è permesso comandare solo un'unità (eccetto per il castling, ma questa è una combinazione di mosse chiaramente definita). Ciò provoca 5 ^ N possibili mosse per N unità per ogni "posizione" (termine di scacchi), se si deciderà solo tra "sposta nord, sud, ovest, est O fermata" per ogni unità. Puoi risolverlo suddividendo il comando complesso nei comandi di basso livello: ad es. Scegli l'azione per l'unità A, vai in profondità e decidi per l'unità B .... decidi per l'unità N ... e poi termina questo turno. Ma questo da solo non cambia la complessità! È necessario ottimizzare l'ordine in cui le azioni sono assegnate alle unità (ad esempio prima unità B, C, D e quindi unità A). È possibile registrare l'impatto della decisione per ciascuna unità durante l'ultimo calcolo e quindi ordinare per importanza. In questo modo la potatura alfa-beta può essere utilizzata molto presto per eliminare qualsiasi cattiva combinazione dall'albero di ricerca. La massima priorità dovrebbe essere sempre "non fare più nulla e terminare il tuo turno" (potatura con mossa nulla) in ogni iterazione. In questo modo è possibile "saltare" assegnando la maggior parte delle attività alla maggior parte delle unità e lasciarle semplicemente continuare ciò che hanno fatto prima. In questo modo la ricerca andrà rapidamente in profondità semplicemente dando un'occhiata alle unità "critiche" (ad esempio quelle realmente in combattimento in questo momento). Assicurati di comandare ogni unità solo una volta ... Puoi anche usare un po 'di casualità per assicurarti che anche le unità "importanti" ricevano un comando di volta in volta. In particolare, le unità stanno finendo un lavoro (ad es
Approfondimento iterativo + cache / tabella hash
Quindi, puoi "approfondire l'interazione" per approfondire sempre di più fino a quando non viene raggiunto un limite di tempo. Quindi cercherai più a fondo se ci sono meno unità e avrai sempre qualche "risultato" se smetti di cercare una soluzione migliore. L'approfondimento iterativo richiederebbe l'uso di una tabella hash per memorizzare nella cache i risultati precedenti delle ricerche. Ciò consente anche di riutilizzare alcuni dei risultati della ricerca dell'ultima svolta (il ramo dell'albero di ricerca che copre i comandi effettivamente eseguiti nell'ultima svolta). Per implementarlo, hai bisogno di un'ottima funzione di hashing (dai un'occhiata al "tasto zobrist"), che può essere aggiornato iterativamente. Aggiornare la chiave hash significa che puoi semplicemente prendere la chiave hash della vecchia "posizione" e puoi semplicemente dare il calcio nella modifica della posizione (es. togliere l'unità in posizione x e metterla in posizione y). In questo modo il calcolo della chiave hash è rapido e non è necessario elaborare l'intera situazione delle schede per calcolarla, solo per verificare se l'hash contiene una voce precedente per questa posizione. In un certo senso è necessario assicurarsi che non si verifichino collisioni di hash.
Comportamento non deterministico
Il comportamento non deterministico è un problema per le ricerche min / max. Ciò significa che non è sicuro se colpirai un bersaglio attaccato (ad es. La probabilità è del 10%). Quindi non puoi semplicemente pianificare questo accada. In tal caso, è necessario modificare l'algoritmo e inserire uno strato "probabilty". È un po 'come "è il turno delle probabilità". Ogni risultato indipendente deve essere considerato separatamente. La valutazione attraverso questo "strato" di profondità deve quindi essere campionata (campionamento monte carlo) e il risultato della valutazione approfondita deve essere ponderato dalla probabilità dell'evento. Risultati diversi del livello di probabilità devono essere considerati come mosse avversarie diverse (ma invece di min / max deve essere calcolata la "media"). Ciò ovviamente aumenterà la complessità dell'albero di ricerca.
Sommario
Quando si applicano tutte quelle tecniche (che sono tutte utilizzate dagli attuali motori di scacchi) a un gioco deterministico, si sarà sicuramente in grado di ottenere risultati ragionevoli anche per un gioco. Per i giochi non deterministici, questo sarà probabilmente più complicato, ma penso che sia comunque gestibile.
Una buona risorsa per la spiegazione di tali tecniche (per gli scacchi) è http://chessprogramming.wikispaces.com/
Puoi persino implementare una sorta di casualità diretta nelle ricerche min / max. Invece di investigare deterministicamente i risultati migliori prima in ogni iterazione, puoi semplicemente randomizzare questo e lasciare che il suo ordine sia deciso da una distribuzione di probabilità basata sulle valutazioni correnti ...