Consapevolezza situazionale nella ricerca di percorsi


11

Supponi di dover trovare il percorso più breve attraverso un sotterraneo, in cui alcuni passaggi ti vengono aperti solo dopo che alcuni oggetti sono stati raccolti, come porte e chiavi bloccate, per esempio.

La normale reazione intestinale alle parole "percorso più breve" sarebbe ovviamente A *. Ma A * fallirebbe in un tale ambiente, poiché vedo molti problemi che definiscono un euristico affidabile e, inoltre, è molto probabile che un nodo debba essere visitato più volte, il che non è possibile anche nell'A * convenzionale e rendere più difficile l'euristica.

Quello a cui ho pensato è semplicemente cercare un percorso dall'inizio della prigione alla fine, ignorando qualsiasi porta bloccata. Dopo aver trovato questo percorso, per ciascuna delle porte che ci bloccano, verrebbe cercato e attraversato un percorso aggiuntivo che cerca la chiave appropriata e torna alla porta prima ancora che la porta venga raggiunta. Lo stesso sistema verrebbe utilizzato per gestire una situazione in cui il percorso verso una chiave necessaria per aprire una porta viene nuovamente bloccato da un'altra porta, che deve essere aperta per prima.

Un grosso problema che vedo con la mia soluzione è che dopo aver trovato tutti i percorsi inclusi quelli per l'acquisizione degli oggetti, la distanza totale percorsa dall'agente potrebbe non essere la più piccola possibile, poiché potrebbero esserci altre porte bloccate più lontane dall'obiettivo ma hanno la chiave appropriata molto più facilmente disponibile. A * avrebbe trascurato queste porte al primo passaggio in cui le porte bloccate venivano semplicemente ignorate.

Sono sicuro di non essere il primo a provare a risolvere questo problema e apprezzerei alcuni input sul problema.


Non so come sia implementato il normale A *, ma ho visto un'implementazione che aveva vari percorsi con una scala di "peso", che avrebbe cambiato quanto fossero attraenti i vari percorsi. Non potresti calcolare tutti i possibili percorsi e quindi impostare il "peso" dei percorsi che attraversano una porta chiusa all'infinito positivo? Ciò farebbe sembrare quel percorso infinitamente lungo e quindi non verrà mai utilizzato. Questo è ovviamente applicabile se si precalcolano i percorsi invece di farlo per ogni entità ogni aggiornamento.
William Mariager,

Grazie per la risposta, ma quello che stai dimenticando è che sbloccare una porta potrebbe essere l'unico modo per raggiungere il nodo obiettivo, nel qual caso l'algoritmo che hai citato non troverebbe un percorso. Oppure, se il peso del percorso bloccato è semplicemente infinito, sceglierebbe uno dei percorsi bloccati e starebbe davanti al mio problema originale.
Marc Müller,

Risposte:


8

Il modo per gestire una situazione del genere in modo ottimale utilizzando A * semplice è quello di espandere lo spazio di ricerca. Cioè, immagina che esista una copia separata del sotterraneo per ogni combinazione di oggetti che il tuo personaggio potrebbe trasportare.

In ogni copia del sotterraneo, le porte che sono percorribili sono esattamente quelle che possono essere passate usando il corrispondente set di oggetti. L'unico modo per passare da una copia del sotterraneo a un altro è quello di stare in piedi sulla posizione di un oggetto e raccoglierlo.

È possibile estendere questo trucco per includere altri cambiamenti di stato, come gli interruttori che possono aprire e / o chiudere le porte. Potresti anche consentire al giocatore di rilasciare oggetti, sebbene ciò possa complicarsi poiché lo stato deve quindi includere la posizione di ciascun oggetto lasciato cadere, aumentando enormemente lo spazio di ricerca potenziale.

Un'ottimizzazione molto utile è quella di precalcolare i percorsi più brevi da ogni porta (in realtà, ogni lato di ogni porta) e da un elemento a ogni altra porta / oggetto raggiungibile, supponendo che tutte le porte siano bloccate . Una volta che hai quei percorsi, puoi semplicemente trattare ciascuno di essi come un bordo ponderato in un grafico che collega queste posizioni significative tra loro e ignorare tutte le altre posizioni.

Ad esempio, supponi che il tuo sotterraneo abbia dieci porte e cinque chiavi. Quindi ci saranno 2 * 10 + 5 = 25 posizioni significative e 2 ^ 5 = 32 possibili combinazioni di elementi, per un totale di 25 * 32 = 800 nodi nell'intero spazio di ricerca. Questo è un numero molto modesto, soprattutto perché è probabile che gran parte dello spazio di ricerca non sia raggiungibile.


5

Da un punto di vista del mondo reale: se tu fossi diretto da A a B e hai trovato una porta D sulla tua strada che era chiusa a chiave, ti renderesti conto che devi trovare la chiave D. Quindi se la tua IA è inconsapevole come il tipico essere umano è , ciò implicherebbe lo scouting della chiave, che è un insieme di minuscoli passi di esplorazione in sé e per sé. D'altra parte potresti desiderare che la tua IA sappia, prima ancora di tentare un percorso, che ci sia una porta chiusa su quel percorso, e in quel caso probabilmente saprà anche dove trovare la chiave.

In entrambi i casi, il problema riguarda la connettività a due livelli. A livello "sul campo", sai che puoi sempre muoverti in sicurezza all'interno di una zona indivisa ... indivisa da porte chiuse, cioè. È qui che puoi usare liberamente la tua attuale implementazione di pathfinding A *. (In un esempio semplicistico, potresti vedere una zona come una stanza singola. Non puoi accedere a nessun'altra stanza senza aprire una porta. In realtà, potrebbe essere un'intera regione del tuo sotterraneo.) Questa è la base del tuo movimento delle entità, ma è un po 'come camminare con gli occhi bassi, invece di sorvegliare l'area intorno a te per primo - è probabile che passi in un lampione. O in questo caso, una porta chiusa a chiave. Quindi le tue mappe a livello del suolo su cui corre A * devono limitare il giocatore al movimento solo all'interno della zona corrente.

Successivamente, c'è una mappa di livello superiore, che è più topologica che di natura topografica. Non si preoccupa davvero dei dettagli sul terreno degli ostacoli e così via, si preoccupa solo della connettività tra le zone. Questa mappa topologica contiene connessioni tra le zone pari che attualmente hanno una porta chiusa tra loro, poiché mostra la connettività ideale di tutte le zone del sotterraneo. Nei suoi bordi - ognuno dei quali rappresenta una porta tra le zone - memorizza quale chiave è ancora necessaria, se presente, per aprire quella porta, altrimenti è considerata aperta. Quindi, cercando questo grafico per il percorso più breve, dovrebbe limitare quel percorso trovato solo ai percorsi che sono già aperti , controllando i dati nei bordi durante l'esecuzione della ricerca. La connettività qui non implica apertura, piuttosto implica potenziale apertura.

Quando vuoi spostarti in un punto che rientra in una zona separata, devi prima cercare nella mappa di livello superiore per trovare un percorso. (A * o qualsiasi altro algoritmo di percorso più breve può essere utilizzato a questo livello.) Una volta trovato un percorso, quella mappa di livello superiore dovrebbe anche fornire informazioni su quale porta è necessario utilizzare per passare dalla zona corrente all'altra zona. Ora, nella zona locale, puoi eseguire l'intelligenza artificiale a livello del suolo per raggiungere quella porta. Una volta raggiunta la porta, il tuo personaggio può passare attraverso quella porta / portale. Ora è nella zona B. Se questa è la zona bersaglio, può usare la navigazione a livello del suolo per andare alla chiave. In caso contrario, è necessario ripetere il passaggio uno fino a raggiungere la zona target.

C'è la possibilità che una chiave venga cercata dietro una porta chiusa ... e che anche la chiave di quella porta sia ... e così via fino alla nausea. Questo è essenzialmente un problema di risoluzione delle dipendenze e ci sono alcuni modi per affrontarlo, uno dei quali è Petri Nets. Vedere questo eccellente documento.

PS. Se stai creando il tuo dungeon in modo procedurale, allora mentre lo fai, puoi archiviare informazioni sull'ordinamento delle dipendenze, a condizione che tu conosca già la posizione iniziale del giocatore.


2

La normale reazione intestinale alle parole "percorso più breve" sarebbe ovviamente A *. Ma A * fallirebbe in un tale ambiente, poiché vedo molti problemi che definiscono un euristico affidabile e, inoltre, è molto probabile che un nodo debba essere visitato più volte, il che non è possibile anche nell'A * convenzionale e rendere più difficile l'euristica.

Innanzitutto, un euristico ammissibile non deve essere perfetto. Deve solo essere sottovalutato e deve essere meglio di niente. Dato che stai lavorando a distanze reali, sembra probabile che A * sarebbe almeno di qualche aiuto, e anche se l'euristica non migliorasse molto la ricerca, probabilmente sarebbe comunque meglio di una ricerca ordinaria o simili.

In secondo luogo, A * può visitare un nodo tutte le volte che vuoi. Ricorda che A * non è un algoritmo di ricerca del percorso ma un algoritmo di ricerca. Cerca tra gli stati. Nei giochi spesso identifichiamo uno stato con una posizione, perché non ci importa di come tu abbia raggiunto quello stato - quanto breve sia stato il percorso per arrivarci. Tuttavia, in un problema come questo, lo stato è una combinazione della posizione più qualsiasi altro stato rilevante come le chiavi in ​​mano.

È vero, tuttavia, che queste complicazioni si sposteranno A * dai regni di "molto efficiente" a "avrà successo, ma probabilmente non nella scala temporale che richiedo". Qual è il calendario richiesto? In effetti, perché hai bisogno di fare questo: hai davvero bisogno del percorso più breve o sarebbe sufficiente un percorso ragionevole?

Quello a cui ho pensato è semplicemente cercare un percorso dall'inizio della prigione alla fine, ignorando qualsiasi porta bloccata. Dopo aver trovato questo percorso, per ciascuna delle porte che ci bloccano, verrebbe cercato e attraversato un percorso aggiuntivo che cerca la chiave appropriata e torna alla porta prima ancora che la porta venga raggiunta.

È facile dimostrare che un tale sistema sarebbe subottimale. Da dove inizieresti il ​​percorso aggiuntivo? Se dall'inizio, hai perso tempo a tracciare il percorso originale verso la porta. Se dalla fine, posizionare una chiave vicino all'inizio significa che il percorso attraversa la mappa due volte quando una volta sarebbe sufficiente. Se si tenta di calcolare i punti di unione ottimali per i percorsi da e verso la porta e il percorso originale, ciò produrrà un risultato ottimale ma richiederà un uso intensivo delle risorse a causa del numero di permutazioni e della difficoltà a formare un'euristica per semplificare la ricerca. Se aggiungi più chiavi al problema, hai il problema del commesso viaggiatore che non è facile da risolvere in modo efficiente.

Quello che tenterei, se è possibile rilassare il criterio del "percorso più breve", è questo:

  • Crea un grafico di alto livello che contenga solo posizioni importanti: posizioni chiave, posizioni delle porte, posizioni all'interno di aree bloccate e annota le distanze in linea retta tra di esse. Se la tua mappa si divide già in stanze o altre posizioni discrete, va benissimo.
  • Usa A * per trovare un percorso attraverso questo grafico, dall'inizio alla fine. La normale euristica a distanza cartesiana dovrebbe essere sufficiente per mantenerla gestibile.
  • Ora, con questo percorso semplificato tra questi punti di passaggio, utilizzare nuovamente A * per tracciare un percorso di basso livello da un punto di passaggio a quello successivo.
  • Unisci questi percorsi di basso livello insieme per formare l'intero percorso.

Una volta che ho funzionato, prenderei in considerazione alcune piccole ottimizzazioni - ad es. ponderare le aree con le chiavi in ​​modo più indulgente in modo che il percorso di basso livello abbia maggiori probabilità di fare piccole deviazioni per raccogliere le chiavi.


0

con le informazioni che hai fornito penso che puoi usare A * con solo una piccola modifica. in un normale algoritmo A *, contrassegni tutti i nodi mentre li passi per assicurarti di non passarli mai più. Questa è la parte esatta che crea problemi con gli Articoli. Il cambiamento chiave è ricordare quali erano i tuoi oggetti quando in precedenza passavi da un nodo. ecco un codice sudo che spiega cosa intendo:

if (nodestoCheck.notempty())
    newNode = nodeToCheck.first;
    if (notpassed(newNode.pos, newNode.items))
        if (room(newNode).containItem)
            add NewNode + room(NewNode).items 
        else
            do normal A* algorithm for new Node

con questo algoritmo si inizia innanzitutto a controllare tutti i nodi senza alcun elemento. c'è un'alta possibilità che il tuo primo gruppo di ricerca finisca bloccato da alcune porte. ma troverà una chiave per quella porta prima che perquisisca tutte le stanze. da quella chiave si avvia una nuova ricerca con quella chiave specifica. questa volta quando raggiungi la porta puoi passarla. la stessa routine continua fino a quando non trovi la tua via d'uscita dal sotterraneo. l'unico problema potrebbe essere il consumo di memoria ogni volta che ci sono molte porte e chiavi. anche se non sarà un problema per almeno 10 o 15 chiavi.


0

Perché non usi semplicemente la normale A * e modella porte bloccate come regioni impraticabili? una volta che prendi la chiave (cammina sul riquadro delle chiavi?), quella particolare porta chiusa a chiave in una regione percorribile.

Ciò significa che il tuo path-finder cercherà il percorso keyless più breve e, se trova le chiavi lungo il percorso, lo incorporerà nel suo percorso se ciò aiuta.

Mi sembra abbastanza ragionevole. Non è perfetto, ma è una soluzione semplice al problema.

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.