Obviamente, tratar de aplicar el algoritmo min-max en el árbol completo de movimientos funciona solo para juegos pequeños (pido disculpas a todos los entusiastas del ajedrez, por "pequeño" no quiero decir "simplista"). Para los juegos de estrategia típicos por turnos donde el tablero suele ser más ancho que 100 fichas y todas las piezas de un lado pueden moverse simultáneamente, el algoritmo min-max no es aplicable.
Me preguntaba si un algoritmo parcial min-max que se limita a configuraciones de placa N en cada profundidad no podría ser lo suficientemente bueno. Usando un algoritmo genético, podría ser posible encontrar una serie de configuraciones de placa que sean buenas para la función de evaluación. Con suerte, estas configuraciones también podrían ser buenas para objetivos a largo plazo.
Me sorprendería si esto no se hubiera pensado antes y probado. Lo tiene? ¿Como funciona?
fuente
Respuestas:
Depende de la mecánica del juego. Game tree min-max puede ser inaplicable en general, pero tal vez se aplique en algunas áreas. Es común que algunas ubicaciones en un mapa sean estratégicamente importantes. Min-max puede aplicarse a un nivel estratégico para cuál de esas ubicaciones controlar. A nivel táctico, para los cuadrados x alrededor de cada ubicación estratégica, min-max podría usarse para decidir cómo se despliegan las unidades para capturarlo y defenderlo.
fuente
Este no es un algoritmo de minimax, sin embargo, los responsables de la IA de Killzone lanzaron un documento basado en las funciones de evaluación de posición que también usa la IA de algunos ajedrez.
Es muy simple, ya que todo lo que hace es elegir un puesto en el tablero basado en el conocimiento actual del agente. Entonces, si el agente tiene poca salud, las posiciones más alejadas de su enemigo recibirán una puntuación más alta, ya que es más deseable estar fuera del alcance del enemigo.
El documento se puede encontrar en AI Game Programming Wisdom 3 y tiene el título Evaluación de posición táctica dinámica.
Puede encontrar un borrador del documento en línea aquí:
http://www.cgf-ai.com/docs/straatman_remco_killzone_ai.pdf
Espero que ayude.
fuente
No creo que sea lo suficientemente bueno. Elegir las configuraciones de N específicas, cuántas y cuáles, sería prácticamente imposible en algo tan complejo. Recuerda que si tu juego presenta recursos infinitos o algo similar, entonces puede haber círculos en cómo se puede jugar, haciendo que la explotación de una IA sea relativamente fácil.
fuente
Sugeriría al menos implementar min-max con poda alfa-beta.
Sin intentarlo y decidir que no es práctico (es decir, un rendimiento terrible), y sin más antecedentes sobre la mecánica del juego, no veo por qué piensas que min-max es inaplicable.
El tamaño del tablero es potencialmente un problema, pero con la poda, descartar las rutas perdedoras permite una búsqueda más profunda con la misma cantidad de cómputo, por lo que quizás las áreas más grandes del tablero no serán un problema cuando se poden. Además, asumir que el tamaño del tablero en sí mismo es un problema puede ser prematuro, no es tanto el tamaño del tablero como la complejidad de la mecánica y cuántos movimientos son posibles desde cada posición del tablero. Si su juego tiene un área grande pero escasamente poblada, el número de movimientos posibles de cada estado del tablero puede no ser muy diferente de si el tablero fuera lo suficientemente grande como para caber todas las piezas. Por supuesto, si tiene un tablero gigantesco que está lleno al 90% y todo se puede mover a cualquier lugar cada turno, requerirá mucha búsqueda.
Tampoco estoy seguro de por qué el movimiento simultáneo es un problema inherente. Mientras realice la transición de un estado de placa discreto a otro y tenga una función de evaluación, el algoritmo debe aplicarse.
Supongo que necesita tener una función de evaluación de todos modos, e independientemente de la búsqueda que utilice, la función de evaluación es donde probablemente vaya la mayor parte del trabajo. El algoritmo min-max con poda en sí es muy simple de implementar, algo que probablemente pueda hacer en una o dos horas y gran parte del trabajo de infraestructura como almacenamiento del estado de la placa, evaluación, generación de movimiento, probablemente sea el mismo independientemente de búsqueda en la que te conformas.
fuente
El ganador del desafío de Google AI de 2011 usó min-max (de profundidad 1). Otro concursante superior utilizó muestreo aleatorio . Este concursante mencionó que una combinación de muestreo min-max y aleatorio, que es básicamente lo que describí en mi pregunta, funcionó mal. Esto lo resuelve, supongo.
Por otro lado, muestra que es posible usar min-max en juegos grandes. Sin embargo, parece que era necesario limitarlo a grupos pequeños de hormigas, trabajar con el conjunto completo de todas las hormigas probablemente hubiera sido demasiado lento. Otra observación interesante es que una profundidad de 1 fue suficiente. Nosotros (los humanos) nos hemos vuelto bastante buenos jugando al ajedrez, y una IA para este juego necesita árboles de búsqueda mucho más profundos para ser un desafío. Nuevos juegos más complejos no se han jugado y estudiado durante tanto tiempo, y las IA más tontas pueden tener suficiente valor de entretenimiento.
fuente
La idea básica de una IA de ajedrez es hacer una lista de todos los movimientos posibles del mejor movimiento estimado actualmente, luego calificarlos y repetir el proceso. Elimina a aquellos con muy pocas posibilidades, ya que no se tomarán (o se puede suponer que no se tomarán, ya que no parecen dar una ventaja).
La idea básica requiere que haga una lista de todos los movimientos posibles, y que repita ese proceso para todos esos movimientos, etc. Esto es posible en el ajedrez (donde la lista de los próximos movimientos probables es efectivamente enumerable; un tablero de ajedrez inicial tiene 20 movimientos posibles ) y hasta cierto punto para otras cosas como backgammon, damas y resolver un cubo de Rubik.
Si tomo un juego simple por turnos (Civilization 2) como ejemplo, cada uno de tus muchachos puede moverse a un total de 8 casillas (o 24) en un solo turno. Si tienes 10 hombres (que no es mucho, normalmente tienes más para cuando comienza a ser algo interesante) el número total de posibles "movimientos" desde el estado actual (por lo tanto, un solo nivel) ya es 8 ^ 10 o alrededor de 4 mil millones. Incluso si podas el 99.99% de esos, aún no puedes profundizar en el árbol ya que la cantidad de movimientos posibles explota muy rápido.
Agregue a eso que el juego es un poco como el problema del cubo de Rubik, donde solo ve progreso después de unos 10 o 12 movimientos, el problema explota hasta un punto donde las ventajas de un mínimo / máximo estándar solo prevalecen a una capacidad de memoria de más de lo que tu computadora típica tendrá.
En otras palabras, las estrategias que encontrará serán reproducibles pero malas.
Para el problema real, cómo hacer una IA decente, iría en la dirección de un movimiento aleatorio dirigido básicamente (mover a cada chico con un poco de inteligencia básica), evaluación y ajuste. Haga esto en paralelo para 100 o 1000 diferentes y elija el que termine siendo el mejor. Puede retroalimentar los resultados de esto en la dirección inteligente original para ajustarlo nuevamente. Un poco como la simulación de Monte Carlo.
fuente
Para aplicar con éxito min / max a un juego de estrategia por turnos, debes aplicar correctamente todas las técnicas de ajedrez disponibles ...
Función de evaluación
Incluso los motores de ajedrez tienen una fuerza muy mala, si sus funciones de evaluación son malas. La versión más simple de una función de evaluación es: 1 = juego ganado por blanco, -1 = juego ganado por negro, 0 = todos los demás casos; Pero, esto te daría un muy mal desempeño. ¡Lo mismo sucede con tu juego por turnos! Si desea usar min / max (con poda alfa / beta y otras cosas) como en el ajedrez, ¡también debe implementar una función de evaluación razonable! De lo contrario, no puede comparar el rendimiento de esos algoritmos cuando se aplica a su juego de estrategia al caso que se aplica al ajedrez.
Lo que hacen las funciones de evaluación de los motores de ajedrez es evaluar cosas como:
Esas partes de la función de evaluación primero deben "traducirse" a su juego:
Las diferentes clasificaciones deben resumirse mediante la función de ponderación (factor_a * rating_a + factor_b * ranting_b + ...) para todas las unidades ...
En los juegos de estrategia también se deben tener en cuenta los recursos (oro, madera, ...) que quedan.
Si su función de evaluación es lo suficientemente buena, no necesita buscar realmente "profundamente" en el árbol para la mayoría de los casos. Por lo tanto, probablemente solo necesite observar más de cerca las 3 o 10 opciones más prometedoras. Ver el próximo capítulo ...
Posibles movimientos en cada posición
Lo más problemático de usar min / max para juegos de estrategia es que puedes comandar múltiples unidades en un turno, mientras que en el ajedrez solo se te permite comandar una unidad (excepto el enroque, pero esta es una combinación de movimientos claramente definida). Esto causa 5 ^ N movimientos posibles para N unidades para cada "posición" (término de ajedrez), si solo decidiera entre "moverse al norte, sur, oeste, este O parar" para cada unidad. Puede resolver esto dividiendo el comando complejo en los comandos de bajo nivel: por ejemplo, elija la acción para la unidad A, profundice y decida la unidad B ... decida la unidad N ... y luego termine este turno. ¡Pero esto solo no cambia la complejidad! Debe optimizar el orden en que las acciones se asignan a las unidades (por ejemplo, primera unidad B, C, D y luego la unidad A). Puede registrar el impacto de la decisión para cada unidad durante el último cálculo y luego ordenar por importancia. De esta forma, la poda alfa-beta se puede utilizar para eliminar cualquier combinación incorrecta del árbol de búsqueda muy pronto. La prioridad más alta siempre debe ser "no hacer nada más y finalizar su turno" (poda de movimiento nulo) en cada iteración. De esta manera, puede "omitir" la asignación de la mayoría de las tareas a la mayoría de las unidades y dejar que continúen lo que hicieron antes. De esta manera, la búsqueda se profundizará rápidamente con solo echar un vistazo a las unidades "críticas" (por ejemplo, las que realmente están en combate en este momento). Asegúrate de mandar solo cada unidad una vez ... También puedes usar algo de aleatoriedad para asegurarte de que las unidades "importantes" también reciban un comando de vez en cuando. Especialmente, las unidades que terminan algún trabajo (p. Ej.
Tabla de profundización iterativa + almacenamiento en caché / hash
Luego, puede "profundizar de manera interactiva" para profundizar más y más hasta que se alcance un límite de tiempo. Por lo tanto, buscará más profundamente si hay menos unidades, y siempre tendrá algún "resultado" si deja de buscar una solución mejor. La profundización iterativa requeriría usar una tabla hash para almacenar en caché los resultados anteriores de las búsquedas. Esto también permite reutilizar algunos de los resultados de la búsqueda de los últimos turnos (la rama del árbol de búsqueda que cubre los comandos que realmente se ejecutaron en el último turno). Para implementar esto, necesita una función hash muy buena (eche un vistazo a la "clave zobrist"), que puede actualizarse de forma iterativa. Actualizar la clave hash significa que puede tomar la clave hash de la antigua "posición" y simplemente iniciar el cambio de posición (p. Ej. retire la unidad en la posición xy colóquela en la posición y). De esta manera, calcular la clave hash es rápido y no necesita procesar toda la situación de los tableros para calcularlo, solo para verificar si el hash contiene una entrada anterior para esta posición. En cierto modo, debe asegurarse de que no ocurran colisiones de hash.
Comportamiento no determinista
El comportamiento no determinista es un problema para las búsquedas mínimas / máximas. Esto significa que no está seguro si golpeará a un objetivo atacado (por ejemplo, la probabilidad es del 10%). Entonces no puedes simplemente planear que esto suceda. En ese caso, debe modificar el algoritmo y poner una capa de "probabilidad" en el medio. Es un poco como "es el turno de las probabilidades". Cada resultado independiente debe considerarse por separado. La evaluación a través de esta "capa" de profundidad debe ser muestreada (muestreo de Monte Carlo) y el resultado de la evaluación en profundidad debe ser ponderado por la probabilidad de ocurrencia. Los diferentes resultados de la capa de probabilidad deben considerarse como diferentes movimientos del oponente (pero en lugar de min / max se debe calcular el "promedio"). Por supuesto, esto aumentará la complejidad del árbol de búsqueda.
Resumen
Al aplicar todas esas técnicas (que son utilizadas por los motores de ajedrez actuales) a un juego determinista, seguramente también podrá lograr resultados razonables para un juego. Para juegos no deterministas, esto será probablemente más complicado, pero creo que aún es manejable.
Un buen recurso para explicar esas técnicas (para el ajedrez) es http://chessprogramming.wikispaces.com/
Incluso puede implementar algún tipo de aleatoriedad dirigida en búsquedas mínimas / máximas. En lugar de investigar deterministamente los mejores resultados primero en cada iteración, puede aleatorizar esto y dejar que su orden se decida por una distribución de probabilidad que se base en las evaluaciones actuales ...
fuente