Estoy trabajando en un juego con mapas que se parecen a cerraduras y rompecabezas clave . La IA necesita navegar hacia una meta que puede estar detrás de una puerta roja cerrada, pero la llave roja puede estar detrás de una puerta azul cerrada, y así sucesivamente ...
Este rompecabezas es similar a una mazmorra estilo Zelda, como esta imagen:
Para llegar a la Meta, debes derrotar al Jefe, lo que requiere pasar por el pozo, lo que requiere recoger la Pluma, lo que requiere recoger la Llave
Las mazmorras de Zelda tienden a ser lineales. Sin embargo, necesito resolver el problema en el caso general. Asi que:
- El objetivo podría requerir uno de un conjunto de claves. Entonces quizás necesites obtener la llave roja o la azul. ¡O podría haber una puerta desbloqueada en el largo camino!
- Podría haber varias puertas y llaves de un tipo. Por ejemplo, podría haber varias llaves rojas en el mapa, y recolectar una otorgará acceso a todas las puertas rojas.
- El objetivo puede ser inaccesible porque las llaves correctas están detrás de puertas cerradas
¿Cómo realizaría la búsqueda de ruta en dicho mapa? ¿Cómo se vería el gráfico de búsqueda?
Nota: el último punto sobre la detección de objetivos inaccesibles es importante; A *, por ejemplo, es extremadamente ineficiente si el objetivo es inaccesible. Me gustaría tratar esto de manera eficiente.
Suponga que la IA sabe dónde está todo en el mapa.
fuente
Respuestas:
La búsqueda de ruta estándar es suficiente : sus estados son su ubicación actual + su inventario actual. "mudarse" es cambiar de habitación o cambiar el inventario. No está cubierto en esta respuesta, pero no es un esfuerzo adicional, es escribir una buena heurística para A *: realmente puede acelerar la búsqueda al preferir recoger cosas en lugar de alejarse, prefiriendo desbloquear una puerta cerca del objetivo sobre buscar un largo camino, etc.
Esta respuesta ha recibido muchos votos positivos desde que llegó primero y tiene una demostración, pero para una solución mucho más optimizada y especializada, también debe leer la respuesta "Hacerlo al revés es mucho más rápido" /gamedev/ / a / 150155/2624
Prueba de concepto Javascript completamente operativa a continuación. Perdón por la respuesta como un volcado de código: en realidad había implementado esto antes de convencerme de que era una buena respuesta, pero me parece bastante flexible.
Para comenzar cuando piense en la búsqueda de rutas, recuerde que la jerarquía de los algoritmos de búsqueda de rutas simples es:
En nuestro caso, simplemente codificar un "estado" como "ubicación + inventario" y "distancias" como "movimiento o uso de elementos" nos permite usar Djikstra o A * para resolver nuestro problema.
Aquí hay un código real que demuestra su nivel de ejemplo. El primer fragmento es solo para comparación: salte a la segunda parte si desea ver la solución final. Comenzamos con una implementación de Djikstra que encuentra el camino correcto, pero hemos ignorado todos los obstáculos y claves. (Pruébelo, puede verlo solo para el final, desde la habitación 0 -> 2 -> 3-> 4-> 6-> 5)
Entonces, ¿cómo agregamos elementos y claves a este código? ¡Simple! en lugar de que cada "estado" comience solo con el número de habitación, ahora es una tupla de la habitación y nuestro estado de inventario:
Las transiciones ahora cambian de ser una tupla (costo, habitación) a una tupla (costo, estado), por lo que pueden codificar tanto "mudarse a otra habitación" como "recoger un artículo"
finalmente, realizamos algunos cambios menores relacionados con el tipo en la función Djikstra (por ejemplo, todavía coincide con un número de sala de meta en lugar de un estado completo), ¡y obtenemos nuestra respuesta completa! Tenga en cuenta que el resultado impreso primero va a la sala 4 para recoger la llave, luego va a la sala 1 para recoger la pluma, luego va a la sala 6, mata al jefe y luego a la sala 5)
En teoría, esto funciona incluso con BFS y no necesitábamos la función de costo para Djikstra, pero tener el costo nos permite decir "recoger una llave es fácil, pero luchar contra un jefe es realmente difícil, y preferimos retroceder 100 pasos en lugar de luchar contra el jefe, si tuviéramos la opción ":
fuente
Atrás A * hará el truco
Como se discutió en esta respuesta a una pregunta sobre la búsqueda de ruta hacia adelante y hacia atrás , la búsqueda de ruta hacia atrás es una solución relativamente simple para este problema. Esto funciona de manera muy similar a GOAP (Planificación de acción orientada a objetivos), planeando soluciones eficientes y minimizando las preguntas sin objetivo.
Al final de esta respuesta, tengo un desglose de cómo maneja el ejemplo que dio.
En detalle
Pathfind desde el destino hasta el inicio. Si, en su búsqueda de caminos, se encuentra con una puerta cerrada, tiene una nueva rama en su búsqueda de caminos que continúa a través de la puerta como si estuviera desbloqueada, y la rama principal continúa buscando otro camino. La rama que continúa a través de la puerta como si estuviera desbloqueada ya no está buscando al agente de IA, ahora está buscando una llave que pueda usar para pasar por la puerta. Con A *, su nueva heurística es la distancia a la tecla + la distancia al agente de IA, en lugar de solo la distancia al agente de IA.
Si la rama de la puerta desbloqueada encuentra la llave, continúa buscando al agente de IA.
Esta solución se hace un poco más complicada cuando hay varias claves viables disponibles, pero puede ramificar en consecuencia. Debido a que las sucursales tienen un destino fijo, aún le permite usar una heurística para optimizar la búsqueda de ruta (A *), y con suerte las rutas imposibles se cortarán rápidamente, si no hay forma de evitar la puerta cerrada, la rama que no No pasar por la puerta se queda sin opciones rápidamente y la rama que atraviesa la puerta y busca la llave continúa por sí sola.
Por supuesto, donde hay una variedad de opciones viables disponibles (múltiples llaves, otros elementos para sortear la puerta, un largo camino alrededor de la puerta), se mantendrán muchas ramas, lo que afectará el rendimiento. Pero también encontrará la opción más rápida y podrá usarla.
En acción
En su ejemplo específico, ruta de acceso desde el objetivo hasta el inicio:
Nos encontramos rápidamente con una puerta de jefe. La rama A continúa por la puerta, ahora buscando un jefe para luchar. La rama B permanece atascada en la habitación y pronto expirará cuando descubra que no hay salida.
La Rama A encuentra al jefe y ahora está buscando el Inicio, pero se encuentra con un pozo.
La rama A continúa sobre el hoyo, pero ahora está buscando la pluma, y en consecuencia hará una línea de abeja hacia la pluma. Se crea la rama C, que trata de encontrar una forma de rodear el pozo, pero caduca tan pronto como no puede. Eso, o se ignora por un tiempo, si su heurístico A * encuentra que la Rama A todavía parece más prometedora.
La rama A se encuentra con la puerta cerrada y continúa a través de la puerta cerrada como si estuviera desbloqueada, pero ahora está buscando la llave. La rama D también continúa a través de la puerta cerrada, todavía buscando la pluma, pero luego buscará la llave. Esto se debe a que no sabemos si necesitamos encontrar la llave o la pluma primero, y en lo que respecta a la búsqueda de caminos, el Inicio podría estar al otro lado de esta puerta. La rama E intenta encontrar un camino alrededor de la puerta cerrada, y falla.
La rama D encuentra rápidamente la pluma y continúa buscando la llave. Se le permite pasar nuevamente por la puerta cerrada, ya que todavía está buscando la llave (y está retrocediendo en el tiempo). Pero una vez que tenga la llave, no podrá pasar por la puerta cerrada (ya que no pudo pasar antes de encontrar la llave).
Las ramas A y D continúan compitiendo, pero cuando la rama A alcanza la llave, está buscando la pluma, y no podrá alcanzarla porque tiene que pasar por la puerta cerrada nuevamente. La Rama D, por otro lado, al alcanzar la tecla, dirige su atención al Inicio y la encuentra sin complicaciones.
La rama D gana. Ha encontrado el camino inverso. La ruta final es: Inicio -> Clave -> Pluma -> Jefe -> Objetivo.
fuente
Editar : esto está escrito desde el punto de vista de una IA que está buscando explorar y descubrir un objetivo, y no conoce la ubicación de las llaves, cerraduras o destinos con anticipación.
Primero, suponga que la IA tiene algún tipo de objetivo general. Por ejemplo, "Encuentra al jefe" en tu ejemplo. Sí, quieres vencerlo, pero realmente se trata de encontrarlo. Suponga que no tiene idea de cómo llegar a la meta, solo que existe. Y lo sabrá cuando lo encuentre. Una vez que se cumple el objetivo, la IA puede dejar de trabajar para resolver el problema.
Además, voy a usar el término genérico "cerradura" y "llave" aquí, incluso si puede ser un abismo y una pluma. Es decir, la pluma "desbloquea" el abismo "cerradura".
Enfoque de solución
Parece que comenzarías primero con solo una IA que era básicamente un explorador de laberintos (si piensas en tu mapa como un laberinto). Explorar y mapear todos los lugares a los que puede ir sería el foco principal de la IA. Podría basarse únicamente en algo simple como: "Ir siempre al camino más cercano que he visto pero que aún no he visitado".
Sin embargo, algunas reglas entrarían en vigencia al explorar que podrían cambiar la prioridad ...
Una nota sobre ese último punto. Si tiene que elegir entre visitar un área inexplorada que se ha visto antes (pero no visitada) versus un área inexplorada detrás de una ruta recién desbloqueada, debe hacer que la ruta recién desbloqueada sea la prioridad. Eso es probablemente donde hay nuevas llaves (o cerraduras) que serán útiles. Esto supone que un camino bloqueado probablemente no será un callejón sin salida sin sentido.
Expandiendo la idea con teclas "bloqueables"
Potencialmente, podría tener claves que no se pueden tomar sin otra clave. O llaves cerradas por así decirlo. Si conoce sus antiguas cuevas colosales, necesita tener la jaula de pájaros para atrapar al pájaro, que luego necesitará para una serpiente. Entonces "desbloqueas" al pájaro con la jaula (que no bloquea el camino pero no se puede levantar sin la jaula), y luego "desbloqueas" la serpiente (que bloquea tu camino) con el pájaro.
Entonces agregando algunas reglas ...
Ni siquiera voy a entrar en todo el asunto acerca de cómo llevar una determinada llave podría negar el efecto de otra llave (Cuevas colosales, la caña asusta al pájaro y debe dejarse caer antes de que el pájaro pueda ser recogido, pero se necesita más tarde para crear un puente mágico) .
fuente