Minimax per Bomberman


11

Sto sviluppando il clone del gioco Bomberman e sto sperimentando diversi tipi di intelligenza artificiale. Prima ho usato la ricerca nello spazio degli stati con A * e ora voglio provare un approccio diverso con l'algoritmo Minimax. Il mio problema è che ogni articolo minimax che ho trovato suppone che i giocatori si alternino. Ma in Bomberman, ogni giocatore compie un'azione contemporaneamente. Penso che potrei generare tutti gli stati possibili per un tick di gioco, ma con quattro giocatori e 5 azioni di base (4 mosse e luogo della bomba) dà 5 ^ 4 stati al primo livello dell'albero del gioco. Tale valore aumenterà in modo esponenziale con ogni livello successivo. Mi sto perdendo qualcosa? Ci sono modi per implementarlo o dovrei usare un algoritmo totalmente diverso? Grazie per eventuali suggerimenti


1
Mentre questo è un po 'fuori tema, una cosa che mi piace fare con l'IA è usare obiettivi o personalità per l'IA. Può trattarsi di potenziamenti da accumulo, non aggressivi, cercare vendetta, fretta, ecc. Con obiettivi del genere puoi dire approssimativamente in quale direzione dovresti muoverti e lanciare una bomba solo se avanza i tuoi progressi verso l'obiettivo (se è ragionevolmente vicino a un giocatore che stai cercando o a un blocco che vuoi distruggere).
Benjamin Danger Johnson,

2
Sì, ti mancano alcune cose, ma non mi ringrazierai per averle segnalate perché peggiorano le cose. Non ci sono 5 azioni di base. Alcuni quadrati hanno 5 "mosse" (4 direzioni e rimangono fermi); altri ne hanno 3 (perché sono bloccati in due direzioni); in media è 4. Ma puoi lanciare una bomba mentre corri , quindi in media il fattore di ramificazione è 8. E qualcuno con un potenziamento ad alta velocità può inserirsi in più mosse, aumentando efficacemente il suo fattore di ramificazione.
Peter Taylor,

Ti ho dato la risposta alla tua domanda usando la ricerca dell'albero di monte carlo.
SDwarfs,

Minimax non è semplicemente utile in una situazione con tante scelte come Bomberman. Esaurirai la tua capacità di ricerca prima di andare abbastanza lontano per vedere se una mossa è ragionevole o no.
Loren Pechtel,

Risposte:


8

I giochi di strategia in tempo reale come bomber man hanno dei momenti difficili con l'IA. Vuoi che sia intelligente, ma allo stesso tempo non può essere perfetto.

Se l'IA è perfetta, i tuoi giocatori saranno frustrati. O perché perdono sempre o ottieni 0,3 fotogrammi al secondo.

Se non è abbastanza intelligente, i tuoi giocatori si annoieranno.

La mia raccomandazione è di avere due funzioni AI, una che determina dove va l'IA, l'altra che determina quando è meglio lanciare una bomba. Puoi usare cose come la previsione del movimento per determinare se un nemico si sta muovendo verso un punto che sarà pericoloso se una bomba viene lanciata nella posizione corrente.

A seconda della difficoltà, è possibile modificare queste funzioni per migliorare o ridurre la difficoltà.


2
Il tempo, la frustrazione e la noia non sono un problema. Sto scrivendo tesi di laurea su diversi approcci di intelligenza artificiale in Bomberman e confrontandoli. Quindi, se è perfetto, è meglio. Sono bloccato con quel
minimox in

1
Il problema che incontrerai nell'algoritmo minimax è il tempo di elaborazione. Dovrai tenere traccia di tutte le azioni nemiche e determinare il loro stile di gioco e il tuo stile di gioco in contropartita. Sembra che tu ne sia già consapevole, ma questo può essere un compito abbastanza scoraggiante per un gioco in tempo reale senza rallentare il gioco. Invece di costruire un albero di gioco, dovrai determinare le tue azioni in tempo reale, magari costruire un algoritmo di apprendimento automatico che migliora meglio quanto gioca?
UnderscoreZero

4

Come hai notato, Bomberman è troppo complesso per essere simulato come un gioco a turni. Estrapolare ogni possibile propria decisione più ogni possibile decisione di ogni altro giocatore non funziona.

Invece, dovresti piuttosto usare un approccio più strategico.

Dovresti chiederti: in che modo un giocatore umano prende decisioni mentre gioca a bomberman? Di solito, un giocatore dovrebbe seguire quattro priorità di base:

  1. evitare le aree di esplosione delle bombe
  2. posizionare bombe in modo che gli altri non possano evitare le loro aree di esplosione
  3. raccogliere potenziamenti
  4. posizionare bombe per far esplodere le rocce

La prima priorità può essere soddisfatta creando una "mappa dei pericoli". Quando viene piazzata una bomba, tutte le tessere coperte devono essere contrassegnate come "pericolose". Prima esplode la bomba (tenere a mente le reazioni a catena!), Maggiore è il livello di pericolo. Ogni volta che l'IA nota che si trova in un campo con un pericolo elevato, dovrebbe allontanarsi. Quando traccia un percorso (per qualsiasi motivo), i campi con un livello di pericolo elevato devono essere evitati (possono essere implementati aggiungendo artificialmente un costo del percorso più elevato a loro).

Il calcolo della mappa di pericolo può essere ulteriormente migliorato per proteggere l'IA da decisioni stupide (come entrare in aree alle quali è difficile sfuggire quando un altro giocatore è vicino).

Ciò dovrebbe già creare un'intelligenza artificiale difensiva ragionevole. E che dire dell'offesa?

Quando l'IA si rende conto che è ragionevolmente sicuro in questo momento, dovrebbe pianificare manovre offensive: dovrebbe considerare come può aumentare la mappa di pericolo attorno agli altri giocatori posizionando le bombe stesse. Quando si sceglie un luogo per piazzare una bomba, dovrebbe preferire luoghi vicini, quindi non deve spostarsi così lontano. Dovrebbe anche ignorare le posizioni delle bombe quando la mappa di pericolo risultante non consente una ragionevole via di fuga.


La mia esperienza limitata nel giocare è che di solito devi piazzare più bombe per uccidere un avversario competente - una strategia deve tenerne conto. Ho giocato contro gli AI con approssimativamente la tua strategia, sono abbastanza inefficaci nell'ucciderti a meno che tu non possa essere messo alle strette.
Loren Pechtel,

4

Penso che potrei generare tutti gli stati possibili per un tick di gioco, ma con quattro giocatori e 5 azioni di base (4 mosse e luogo della bomba) dà 5 ^ 4 stati al primo livello dell'albero del gioco.

Corretta! Devi cercare tutte le azioni 5 ^ 4 (o anche 6 ^ 4, dato che puoi camminare in 4 direzioni, fermarti e "mettere una bomba"?) Per ogni tick di gioco. MA, quando un giocatore ha già deciso di muovere, ci vuole del tempo prima che la mossa venga eseguita (ad es. 10 tick di gioco). Durante questo periodo il numero di possibilità si riduce.

Tale valore aumenterà in modo esponenziale con ogni livello successivo. Mi sto perdendo qualcosa? Ci sono modi per implementarlo o dovrei usare un algoritmo totalmente diverso?

È possibile utilizzare una tabella hash per calcolare lo stesso "sottotree" dello stesso stato di gioco solo una volta. Immagina che il giocatore A cammini su e giù, mentre tutti gli altri giocatori "aspettano", finisci nello stesso stato di gioco. È lo stesso di "sinistra-destra" o "destra-sinistra". Anche lo spostamento di "su-poi-a sinistra" e "a sinistra-poi-su" porta allo stesso stato. Utilizzando una tabella hash è possibile "riutilizzare" il punteggio calcolato per uno stato di gioco che è già stato valutato. Ciò riduce parecchio la velocità di crescita. Matematicamente, riduce la base della tua funzione di crescita esponenziale. Per avere un'idea di quanto riduce la complessità, esaminiamo le mosse possibili per un solo giocatore rispetto alle posizioni raggiungibili sulla mappa (= diversi stati di gioco) se il giocatore può semplicemente spostarsi su / giù / a sinistra / a destra / a fine .

profondità 1: 5 mosse, 5 stati diversi, 5 stati aggiuntivi per questa ricorsione

profondità 2: 25 mosse, 13 stati diversi, 8 stati aggiuntivi per questa ricorsione

profondità 3: 6125 mosse, 25 stati diversi, 12 stati aggiuntivi per questa ricorsione

Per visualizzarlo, rispondi a te stesso: quali campi sulla mappa possono essere raggiunti con una mossa, due mosse, tre mosse. La risposta è: tutti i campi con una distanza massima = 1, 2 o 3 dalla posizione iniziale.

Quando usi una HashTable devi solo valutare ogni stato di gioco raggiungibile (nel nostro esempio 25 alla profondità 3) una volta. Considerando che senza una tabella hash è necessario valutarli più volte, il che significherebbe 6125 valutazioni anziché 25 a livello di profondità 3. Il migliore: una volta calcolata una voce di HashTable, è possibile riutilizzarla in fasi temporali successive ...

Puoi anche utilizzare approfondimenti incrementali e sottotitoli di potatura alfa-beta "tagliati" che non vale la pena cercare in modo più approfondito. Per gli scacchi ciò riduce il numero di nodi cercati a circa l'1%. Una breve introduzione alla potatura alfa-beta può essere trovata come video qui: http://www.teachingtree.co/cs/watch?concept_name=Alpha-beta+Pruning

Un buon inizio per ulteriori studi è http://chessprogramming.wikispaces.com/Search . La pagina è legata agli scacchi, ma gli algoritmi di ricerca e ottimizzazione sono abbastanza gli stessi.

Un altro (ma complesso) algoritmo AI - che sarebbe più adatto al gioco - è l'apprendimento delle differenze temporali.

Saluti

Stefan

PS: se riduci il numero di possibili stati di gioco (ad es. Dimensioni molto ridotte della mappa, solo una bomba per giocatore, nient'altro), c'è la possibilità di pre-calcolare una valutazione per tutti gli stati di gioco.

--modificare--

È inoltre possibile utilizzare i risultati calcolati offline dei calcoli minimax per addestrare una rete neuronale. Oppure potresti usarli per valutare / confrontare strategie implementate a mano. Ad esempio, è possibile implementare alcune delle "personalità" suggerite e alcune euristiche che rilevano, in quali situazioni la strategia è buona. Pertanto, dovresti "classificare" le situazioni (ad es. Gli stati di gioco). Questo potrebbe anche essere gestito da una rete neuronale: formare una rete neuronale per prevedere quale delle strategie codificate a mano sta giocando meglio nella situazione attuale ed eseguirla. Ciò dovrebbe produrre decisioni in tempo reale estremamente buone per un gioco reale. Molto meglio di una ricerca con limite di profondità basso che può essere realizzata altrimenti, poiché non importa quanto tempo impiegano i calcoli offline (sono prima del gioco).

- modifica # 2 -

Se ricalcoli le mosse migliori solo ogni 1 secondo, potresti anche provare a eseguire una pianificazione di livello superiore. Cosa intendo con questo? Sai quante mosse puoi fare in 1 secondo. In questo modo puoi creare un elenco di posizioni raggiungibili (ad es. Se si trattasse di 3 mosse in 1 secondo, avresti 25 posizioni raggiungibili). Quindi potresti pianificare come: vai in "posizione xe piazza una bomba". Come alcuni altri hanno suggerito, è possibile creare una mappa di "pericolo", che viene utilizzata per l'algoritmo di routing (come andare in posizione x? Quale percorso dovrebbe essere preferito [ci sono alcune variazioni possibili nella maggior parte dei casi]). Ciò richiede meno memoria rispetto a un'enorme HashTable, ma produce risultati meno ottimali. Ma poiché utilizza meno memoria, potrebbe essere più veloce a causa degli effetti di memorizzazione nella cache (uso migliore delle cache di memoria L1 / L2).

INOLTRE: è possibile effettuare pre-ricerche che contengono solo mosse per un giocatore ciascuna per risolvere le variazioni che risultano perdere. Quindi togli tutti gli altri giocatori dal gioco ... Memorizza le combinazioni che ogni giocatore può scegliere senza perdere. Se ci sono solo mosse perdenti, cerca le combinazioni di mosse in cui il giocatore rimane in vita il più a lungo possibile. Per archiviare / elaborare questo tipo di strutture ad albero è necessario utilizzare un array con puntatori indice come questo:

class Gamestate {
  int value;
  int bestmove;
  int moves[5];
};

#define MAX 1000000
Gamestate[MAX] tree;

int rootindex = 0;
int nextfree = 1;

Ogni stato ha un "valore" di valutazione e si collega ai Gamestates successivi quando si sposta (0 = stop, 1 = su, 2 = destra, 3 = giù, 4 = sinistra) memorizzando l'indice di matrice all'interno di "albero" nelle mosse [0 ] per spostare [4]. Costruire il tuo albero in modo ricorsivo potrebbe apparire così:

const int dx[5] = { 0,  0, 1, 0, -1 };
const int dy[5] = { 0, -1, 0, 1,  0 };

int search(int x, int y, int current_state, int depth_left) {
  // TODO: simulate bombs here...
  if (died) return RESULT_DEAD;

  if (depth_left == 0) {
    return estimate_result();
  }

  int bestresult = RESULT_DEAD;

  for(int m=0; m<5; ++m) {
    int nx = x + dx[m];
    int ny = y + dy[m];
    if (m == 0 || is_map_free(nx,ny)) {
      int newstateindex = nextfree;
      tree[current_state].move[m] = newstateindex ;
      ++nextfree;

      if (newstateindex >= MAX) { 
        // ERROR-MESSAGE!!!
      }

      do_move(m, &undodata);
      int result = search(nx, ny, newstateindex, depth_left-1);
      undo_move(undodata);

      if (result == RESULT_DEAD) {
        tree[current_state].move[m] = -1; // cut subtree...
      }

      if (result > bestresult) {
        bestresult = result;
        tree[current_state].bestmove = m;
      }
    }
  }

  return bestresult;
}

Questo tipo di struttura ad albero è molto più veloce, poiché l'allocazione dinamica della memoria è davvero molto lenta! Ma anche memorizzare l'albero di ricerca è piuttosto lento ... Quindi questa è più una fonte d'ispirazione.


0

Aiuterebbe a immaginare che tutti si alternino?

Tecnicamente, nel sistema sottostante, in realtà lo fanno, ma poiché le cose sono interlacciate e sovrapposte, sembrano funzionare simultaneamente.

Ricorda inoltre che non è necessario eseguire l'IA dopo ogni fotogramma di animazione. Molti giochi casuali di successo eseguono l'algoritmo AI solo una volta ogni due secondi circa, fornendo ai personaggi controllati dall'IA informazioni su dove dovrebbero andare o cosa dovrebbero fare, quindi tali informazioni vengono utilizzate per controllare i personaggi dell'IA sugli altri frame.


Non sto calcolando l'intelligenza artificiale in ogni fotogramma dell'animazione ma in ogni secondo. Ogni secondo il mio ambiente raccoglie le azioni di tutti i giocatori e invia loro un nuovo stato aggiornato.
Billda,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.