language-agnostic artificial-intelligence

language agnostic - ¿Cómo debería comenzar a diseñar un algoritmo de IA para un juego de artillería de guerra?



language-agnostic artificial-intelligence (7)

Aquí está el fondo ... en mi tiempo libre estoy diseñando un juego de guerra de artillería llamado Staker (inspirado en los antiguos juegos BASIC Tank Wars y Scorched Earth ) y lo estoy programando en MATLAB. Su primer pensamiento podría ser "¿Por qué MATLAB? Hay muchos otros idiomas / paquetes de software que son mejores para el diseño del juego". Y tú estarías bien. Sin embargo, soy un idiota y estoy interesado en aprender los aspectos prácticos de cómo diseñarías un juego desde cero, así que no necesariamente quiero usar nada con módulos prefabricados. Además, he usado MATLAB durante años y me gusta el desafío de hacer cosas con él que otros realmente no han intentado hacer.

Ahora, al problema que tenemos entre manos: quiero incorporar IA para que el jugador pueda ir contra la computadora. Acabo de empezar a pensar en cómo diseñar el algoritmo para elegir un ángulo de acimut, un ángulo de elevación y una velocidad de proyectil para alcanzar un objetivo, y luego ajustarlos cada turno. Siento que tal vez estuve pensando demasiado el problema y tratando de hacer que la inteligencia artificial sea demasiado compleja desde el principio, así que pensé en hacer una pausa y pedirle a la comunidad ideas sobre cómo diseñarían un algoritmo.

Algunas preguntas específicas:

  1. ¿Hay referencias específicas para el diseño de IA que sugiera que revise?

  2. ¿Diseñarías los jugadores AI para variar en dificultad de una manera continua (una dificultad de 0 (fácil) a 1 (difícil), todos usando el mismo algoritmo general) o diseñarías algoritmos específicos para un número discreto de jugadores AI ( como un enemigo fácil que dispara en direcciones aleatorias o un enemigo duro que es capaz de dar cuenta de los efectos del viento)?

  3. ¿Con qué tipo de algoritmos matemáticos (descripción de pseudocódigo) comenzarías?

Alguna información adicional: el modelo que uso para simular el movimiento del proyectil incorpora arrastre fluido y el efecto del viento. El "fluido" puede ser aire o agua. En el aire, la densidad del aire (y, por lo tanto, el efecto de arrastre) varía con la altura sobre el suelo en función de algunos modelos atmosféricos simples. En el agua, el arrastre es tan grande que el proyectil generalmente requiere empuje adicional. En otras palabras, el proyectil puede verse afectado por fuerzas distintas de la gravedad.


En una situación real de artillería, todos estos factores se manejarían con fórmulas o simplemente con simulación de fuerza bruta: dispara un caparazón electrónico, aplica todas las fuerzas relevantes y observa dónde cae. Ajuste e intente de nuevo hasta que la carcasa electrónica llegue al objetivo. Ahora tienes tus números para enviar a la pistola.

Dada la complejidad de la situación, dudo que haya una respuesta mejor que la fuerza bruta. Si bien puede precalcular una tabla de efectos de arrastre esperados frente a la velocidad, no puedo ver que valga la pena.

Por supuesto, un juego donde la IA deja caer la primera coraza en tu cabeza cada vez no sería interesante. Una vez que conozcas los valores correctos, tendrás que hacer que la IA sea una mala foto. Aplica un factor aleatorio al disparo y luego camina hacia el objetivo - muévelo 30 + aleatorio (140)% hacia el objetivo verdadero cada vez que dispara.

Editar:

Estoy de acuerdo con la idea de BCS de mejorarlo a medida que pasa el tiempo. Dije eso, pero luego cambié de opinión sobre cómo escribir un montón y luego terminé olvidándome de volver a ponerlo. Cuanto más difícil se supone que es menor, el componente aleatorio debería ser.


Gracias Loren y BCS, creo que has llegado a una idea que estaba considerando (lo que provocó la pregunta n. ° 2 anterior). El pseudocódigo para un turno de IA se vería así:

nSims; % A variable storing the numbers of projectile simulations % done per turn for the AI (i.e. difficulty) prevParams; % A variable storing the previous shot parameters prevResults; % A variable storing some measure of accuracy of the last shot newParams = get_new_guess(prevParams,prevResults); loop for nSims times, newResults = simulate_projectile_flight(newParams); newParams = get_new_guess(newParams,newResults); end fire_projectile(newParams);

En este caso, la variable nSims es esencialmente una medida de "inteligencia" para la IA. Una IA "tonta" tendría nSims = 0, y simplemente haría una nueva suposición cada turno (según los resultados del turno anterior). Una IA "inteligente" refinaría sus tiempos de estimulación nSims por turno al simular el vuelo del proyectil.

Dos preguntas más surgen de esto:

1) ¿Qué entra en la función get_new_guess? ¿Cómo debo ajustar los tres parámetros de disparo para minimizar la distancia al objetivo? Por ejemplo, si un disparo no alcanza el objetivo, puede intentar acercarse ajustando solo el ángulo de elevación, ajustando la velocidad del proyectil solamente o ajustando ambos a la vez.

2) ¿Debería get_new_guess ser el mismo para todas las IA, siendo el valor de nSims el único determinante de "inteligencia"? ¿O debería get_new_guess depender de otro parámetro de "inteligencia" (como guessAccuracy)?


La diferencia entre los juegos de artillería y las situaciones reales de artillería es que todas las partes tienen 100% de información, y que normalmente hay más de 2 oponentes.

Como resultado, su función de evaluación debería considerar qué oponente sería más urgente intentar y eliminar. Por ejemplo, si tengo una muerte fácil al 90%, pero con un 50% de probabilidad de que alguien intente matarme y se pierda dos tiros cerca de mí, es más importante lidiar con esa posibilidad.

Creo que necesitarías alguna forma de evaluar el riesgo que todos te plantean en términos de municiones, ubicación, actividad, historial, etc.


La solución de fuerza bruta de Loren es atractiva, ya que permitiría simples "ajustes de inteligencia" al agregar más iteraciones. Además, los factores de ajuste para la iteración podrían ser parte de la inteligencia, ya que algún valor lo hará converger más rápido.

También para el sistema básico (sin arrastre, viento, etc.) hay una solución cerrada que se puede derivar de un texto de física básico. Haría que la primera suposición fuera eso y luego haría una o más iteraciones por turno. Es posible que desee tratar de encontrar una correlación de corrección empírica para mejorar la primera toma (algo que hará que el promedio de las primeras distribuciones de toma esté más cerca de ser correcto)


Ahora me estoy dirigiendo a la respuesta que publicaste:

Si bien tiene una idea general, no creo que su enfoque sea factible: convergerá demasiado rápido incluso para un valor bajo de nSims. Dudo que quieras más de una iteración de get_new_guess entre shells y muy bien podría necesitar un al azar más allá de eso.

Incluso si puede usar múltiples iteraciones, no sería bueno hacer una dificultad continuamente creciente ya que serán grandes pasos. Me parece que la dificultad debe ser manejada por la aleatoriedad.

Primero, get_initial_guess:

Para empezar, tendría una tabla que divide el mundo en zonas, cuanto mayor es la dificultad, más zonas. Los límites entre estas zonas tendrían potencia precalculada para 45, 60 y 75 grados. Haga un diagrama de prueba, si un proyectil golpea el terreno, inténtelo nuevamente en un ángulo más alto; si 75 hits lo usan de todos modos.

El shell inicial debe dispararse a una potencia aleatoria entre los valores dados para los límites bajo y alto.

Ahora, para get_new_guess:

¿El proyectil golpeó el terreno? Aumenta el ángulo. Creo que habrá una proporción constante de la cantidad de potencia que se necesita aumentar para mantener la misma distancia; tendrás que realizar pruebas al respecto.

Suponiendo que no golpeó una montaña, tenga en cuenta si es corto o largo. Esto te da un límite. La nueva suposición está en algún lugar entre los dos límites (si le falta un límite, use el valor de la tabla en get_initial_guess en su lugar).

Tenga en cuenta qué porcentaje del camino entre los puntos de impacto de límite bajo y alto es el objetivo y elija una potencia que esté muy lejos entre la potencia límite baja y alta.

Probablemente esto sea demasiado preciso y probablemente requiera cierta asignación al azar. He cambiado de opinión sobre agregar un simple% aleatorio. Por el contrario, se deben usar múltiples números aleatorios para obtener una curva de campana.


Otro pensamiento: ¿Estamos lidiando con un sistema donde solo un caparazón está activo a la vez? Hace mucho tiempo implementé un juego de artillería en el que tenías 5 barriles, cada uno con un tiempo de recarga fijo que estaba por encima del tiempo de vuelo máximo posible.

Con eso me encontré usando una estrategia de disparar proyectiles extendidos a lo largo del rango entre mi límite bajo actual y límite alto. Sin embargo, es posible que siendo un simple ser humano no usara una estrategia óptima, esto fue en tiempo real, obtener una ronda tan pronto como el cañón estuvo listo fue más importante que asegurar que se apuntó lo mejor posible ya que convergería bastante rápido, de todos modos. En general, pondría un proyectil en el objetivo en el segundo salvo y el tercero generalmente serían todos hits. (Una muerte requiere matar TODOS los píxeles en el objetivo.)

En una situación de IA, modelaría esto y una estrategia de retener algunos de los barriles para disparar rondas más precisas más tarde. Todavía dispararía una extensión en el rango objetivo, la única pregunta es si utilizaría todos los barriles o no.


Personalmente he creado un sistema así, para el juego web Zwok, usando la fuerza bruta. Disparé muchas tomas en direcciones aleatorias y grabé el mejor resultado. No recomendaría hacerlo de otra manera, ya que la diferencia entre los tiempos, etc. le dará resultados inesperados.