implementación de un agente para un jugador de mario ai

Anuncio
IMPLEMENTACIÓN DE UN AGENTE PARA UN JUGADOR
DE MARIO A.I.
Alejandro Pérez Cruz
David de la Horra Iglesias
Ingeniería de Telecomunicación
Ingeniería de Telecomunicación
Universidad Carlos III de Madrid
Universidad Carlos III de Madrid
NIA: 100072647
[email protected]
NIA: 100066695
[email protected]
RESUMEN
En este documento presentamos una posible implementación de
un agente que pueda jugar al juego SuperMario Bross. con una
cierta inteligencia autónoma.
Categorías y descriptores de temas.
[Inteligencia Artificial]: Agente reactivo que permite interactuar
con el medio y realizar acciones para superar los distintos niveles
del juego SuperMario Bros.
Términos generales
Algoritmos de búsqueda, lenguaje de programación Java, diseño e
implementación de un agente.
2. ESTRATEGIAS DE BÚSQUEDA
Los algoritmos de búsqueda tratan de encontrar, en general, la
solución más apropiada al problema en cuestión. Para ello se parte
de un estado inicial y se trata de alcanzar un estado final deseado
(meta, objetivo) por medio del uso de árboles de decisión en los
cuales se van expandiendo nodos y desechando caminos de
búsqueda según se avanza en el árbol.
Para ello existen diferentes estrategias de búsqueda que definen el
orden para la expansión de nodos y que deben ser evaluadas
según:

Completitud de la solución: hay que evaluar si la
solución se encuentra siempre que esta exista.

Complejidad temporal: en este caso, lo que se debe
evaluar es el número de nodos que han sido generados.

Complejidad espacial: hay que evaluar además el
número de nodos que como máximo se han guardado en
memoria.

Optimalidad de la solución: hay que evaluar si se
encuentra la solución con menor coste.
Palabras Clave
Búsqueda, inteligencia artificial, agentes.
1. INTRODUCCIÓN
A lo largo del siguiente documento expondremos las diferentes
estrategias de búsqueda existentes y las posibles
implementaciones que se deben tener en cuenta para desarrollar
un agente que permita jugar de manera autónoma y con cierta
inteligencia al SuperMario, consiguiendo superar el mayor
número de niveles posibles y con la mayor puntuación posible.
Además se explicará la solución llevada a cabo y nuestra
implementación del agente en Java para lograr un resultado
satisfactorio en la competición para nuestro jugador. Se presentará
pues el algoritmo utilizado (árboles de decisión) y el entorno en el
que se desarrolla nuestra aplicación.
Para evaluar cada estrategia se utilizan unos parámetros, que son:
1)
Factor de ramificación (b).
2)
Profundidad de la solución (d).
3)
Máxima profundidad (m).
Una vez tenemos toda la información necesaria para evaluar
nuestra solución, trataremos de implementar aquella estrategia que
se adecúe más al fin que persigamos y que sea posible con los
recursos de tiempo y memoria de los que se dispone.
En nuestro caso se dispone de información del dominio por medio
de una matriz de 19x19 que nos proporciona información de la
escena en la que se encuentra nuestro Mario y en la que dicho
Mario se encuentra centrado en la posición (9,9) en todo
momento.
Así pues, debido a que tenemos información del dominio puede
ser lógico utilizar algún tipo de estrategia heurística que ayude a
encontrar la solución a nuestro problema, es decir, en nuestro caso
a permitir avanzar a nuestro jugador a lo largo de un nivel sin que
sufra daño alguno.
3. ALGORITMOS
3.3 Algoritmo de pathfinding A*
3.1 Árboles de decisión
Presentamos este algoritmo porque también se recomienda desde
la competición de MarioAI ya que ha dado buenos frutos a
anteriores participantes que lo desarrollaron.
Es la estrategia que hemos seguido para desarrollar nuestro
agente. Consiste en un modelo de predicción usado en el ámbito
de la inteligencia artificial. Permiten construir un diagrama de
decisiones y/o de predicción basados en reglas que sirven para
representar una serie de condiciones que ocurren de forma
sucesiva.
Un árbol tiene una serie de entradas, las cuales pueden ser un
objeto o una situación descrita a partir de un conjunto de atributos.
Como resultado del procesamiento de las entradas y a través de la
estructura del árbol, basada en ciertas reglas, se consigue alcanzar
las hojas del árbol en el que se encuentran las decisiones a tomar
en función de las entradas que se tenían.
Así pues, lo importante en este tipo de algoritmos es definir bien
las reglas de modo que se adapten correctamente a la situación
que se plantea para que la solución que se alcanza sea la más
apropiada dada la situación y el conocimiento del entorno que se
tiene.
3.2 Algoritmos genéticos
Este tipo de algoritmos se desarrolla en múltiples ámbitos de la
inteligencia artificial y era uno de los que se nos proponía
desarrollar desde la página web de la competición de Mario AI y
por eso aparece en esta memoria.
Este algoritmo se clasifica dentro de los algoritmos de búsqueda
en grafos. Además, se demuestra que la búsqueda realizada por
medio de este algoritmo alcanza la solución óptima (el camino de
menor coste entre un nodo origen y uno objetivo) siempre que se
utilice un heurístico admisible, es decir, que no sobreestime el
coste real.
Este algoritmo utiliza una función de evaluación que tiene en
cuenta tanto el coste real del recorrido como el valor heurístico de
los nodos. La función es la siguiente:
( ) = ( ) + ℎ( )
Donde:

g(n): coste sufrido hasta alcanzar n (nodo actual).

h(n): coste estimado desde n hasta la meta.

f(n): coste estimado total hasta la meta pasando por n.
Dicho algoritmo mantiene dos estructuras de datos auxiliares:
nodos abiertos (implementados como una cola con prioridad
ordenada por el valor f(n) de cada nodo) y los nodos cerrados
donde se guarda la información de los nodos que ya han sido
visitados.
Un algoritmo genético es una técnica de búsqueda basada en la
teoría de la evolución de Darwin, que ha cobrado tremenda
popularidad en los últimos años.
Esta técnica se basa en los mecanismo de selección que utiliza la
naturaleza, de acuerdo a los cuales, los individuos más aptos de
una población son los que sobreviven al adaptarse más fácilmente
a los cambios que se producen en su entorno.
Así pues, los algoritmos genéticos son métodos adaptativos que
pueden usarse para resolver problemas de búsqueda y
optimización y que están basados en el proceso genético de los
organismos vivos.
Durante la fase reproductiva se seleccionan los individuos de la
población para cruzarse y producir descendientes que constituirán,
una vez mutados, la siguiente generación de individuos. La
selección de padres se efectúa al azar usando un procedimiento
que favorezca a los individuos mejor adaptados, ya que a cada
individuo se le asigna una probabilidad de ser seleccionado que es
proporcional a su función de adaptación. De este modo, los
individuos bien adaptados se escogerán probablemente varias
veces por generación, mientras que los pobremente adaptados no
se escogerán más que de vez en cuando.
Por lo tanto, un algoritmo genético es un método de búsqueda
dirigida basada en probabilidad. Bajo una condición muy débil
(que el algoritmo guarde siempre al mejor elemento de la
población sin hacerle ningún cambio) se puede demostrar que el
algoritmo converge en probabilidad al óptimo. Es decir, al
aumentar el número de iteraciones, la probabilidad de tener el
óptimo en la población tiende a uno.
En cada paso, se expande el nodo que esté primero en abiertos, y
en caso de que no sea un nodo objetivo, calcula el f(n) de todos
sus hijos, los inserta en abiertos, y pasa el nodo evaluado a
cerrados.
Así pues, este algoritmo es una combinación entre búsquedas de
tipo en anchura con búsquedas en profundidad.
4. AGENTES
Una vez hemos comentado un poco las diferentes estrategias de
búsqueda para ayudarnos a solucionar nuestro problema, vamos a
comentar un poco la teoría que hay por debajo del agente que
debemos desarrollar.

Delegación: capacidad para realizar tareas delegadas por
el usuario u otros agentes.

Movilidad: capacidad de suspender la ejecución a mitad
de una tarea y reanudarla en otro nodo.

Personalidad: capacidad para tener un estado mental que
incluya creencias, deseos, intenciones, motivaciones...
que determinen su comportamiento.

Continuidad temporal: se considera un agente como un
proceso sin fin, ejecutándose continuamente y
desarrollando su función.

Veracidad: asunción de que un agente no comunica
información falsa a propósito.

Benevolencia: asunción de que un agente está dispuesto
a ayudar a otros agentes si esto no entra en conflicto con
sus propios objetivos.
4.1 Definición y principios básicos
Un agente es una entidad capaz de percibir su entorno, procesar
tales percepciones y responder o actuar en su entorno de manera
racional, es decir, de manera correcta y tendiendo a maximizar un
resultado esperado basándose en la evidencia proporcionada por
sus sensores y en el conocimiento del que disponga.
Así pues, un agente es autónomo en tanto en cuanto sus acciones
y elecciones dependen más de su propia experiencia que del
conocimiento introducido sobre el entorno por el programador.
Según Michael Wooldridge un agente inteligente es el que es
capaz de actuar con autonomía de forma flexible, destacando la
reactividad, la proactividad y la habilidad social sobre otras
propiedades.
En general, los agentes poseen las siguientes propiedades:

Autonomía: es la independencia del usuario. El agente
debe ser capaz de tomar decisiones por su cuenta.

Reactividad: el agente debe observar e interactuar con el
entorno.

Proactividad: debe haber una intención de cumplir con
los objetivos fijados mediante planificación y
razonamiento práctico.

Persistencia: es la capacidad para mantener un estado
(estado mental) que no se modifica caprichosamente.

Razonamiento: el agente debe ser capaz de interpretar la
información del entorno, realizar inferencias y tomar las
decisiones oportunas.

Aprendizaje: es la capacidad para cambiar su
conocimiento a partir de la experiencia.

Planificación: se define como la capacidad de construir
planes propios para lograr objetivos a partir de las tareas
que se sabe realizar o podemos pedir a otros.

Comunicación: es la capacidad para entenderse con
otros agentes en un lenguaje expresivo con actos
comunicativos.

Cooperación: es la capacidad para solicitar o dar
servicios a otros agentes y trabajar en cooperación para
conseguir un objetivo común.
Además, presentamos las arquitecturas generales de los agentes:
En nuestro caso, implementamos un agente reactivo debido a su
simplicidad básicamente.
Además, cabe decir que la conducta de una agente rara vez es la
óptima. Esto es debido a que calcular el óptimo de un criterio de
un modo suficientemente bueno para ser considerado razonable es
muy difícil cuando en el problema planteado concurren múltiples
restricciones.
4.2 Familias de agentes
Por último, en este apartado más teórico sobre agentes
describiremos algunas familias:

Agentes colaborativos: son aquellos que principalmente
cooperan con otros agentes.

Agentes personales: actúan par un usuario o un grupo de
usuarios compartiendo tareas, datos, etc.

Agentes de información: investigan y analizan la
información en la red y permiten fusionar la
información de múltiples fuentes.

Agentes móviles: son aquellos que se desplazan para
ejecutarse. Suelen ser agentes de información.

Mario Pequeño: Este estado es el más pequeño de todos
en tamaño, y esto repercute en que tenga que saltar más
que Súper Mario o Mario Fuego para superar el mismo
obstáculo, además de no disponer del botón correr y
echar fuego.
4.3 Estados de Mario
Aunque en nuestra implementación no tenemos en
cuenta el estado en el que se encuentra Mario,
consideramos cultura del juego el que el lector sepa los
diferentes estados en los que se puede encontrar Mario y
las características de las que puede disponer.
4.4 Estados de movimientos


Mario Fuego: Este es el mejor estado en el que puede
encontrarse Mario, en el podrá efectuar todos los
movimientos posible incluyendo correr y echar fuego.
Si Mario es herido por alguna de las criaturas pasará al
estado Súper Mario tras parpadear un tiempo en la
pantalla. Este es por defecto el estado en el que empieza
la partida.
Súper Mario: Mario llega a este estado tras comer una
seta desde Mario o ser herido desde Mario Fuego, podrá
realizar todos los movimientos excepto correr y echar
fuego.
Mario podrá estar en diversos estados a lo largo de la partida,
estos son vitales para posteriormente poder establecer las
reglas de decisión.
Estos estados vienen ya codificados en el paquete que nos
descargamos de [8]
Estos estados son:

Andando: Este movimiento se produce cuando se pulsan
cualquiera de las teclas de dirección izquierda (KEY_
LEFT) o derecha (KEY_RIGTH). Esta acción es
independiente del estado de Mario y también podemos
pasar a cualquier otra acción.

Corriendo: Mario avanza a una velocidad superior a la
normal, esto solo se puede conseguir si se encuentra en
los estados Mario Fuego o Súper Mario.
Para poder llegar a este estado es necesario mantener
pulsadas las teclas de dirección ya sea izquierda o
derecha y la de correr (KEY_SPEED).

Saltando: Esta acción se puede realizar en cualquier
estado de Mario, pero debido al tamaño reducido de
Mario pequeño como es obvio necesitara saltar más para
poder sobrepasar el mismo obstáculo.
Este movimiento contempla desde que presionamos la
tecla de salto hasta que llegamos al punto más alto, el
nivel del salto depende de cuánto tiempo esté pulsada la
tecla de salto (hasta alcanzar un máximo).
Es importante tener en cuenta que para poder iniciar un
salto no puede estar pulsada con anterioridad la tecla de
salto, en ese caso no saltará.

Cayendo: Después de haber efectuado un salto, la
gravedad nos hace caer, en este momento no podremos
impulsarnos más e iremos hacia el suelo.
Esta acción es independiente del estado en que se
encuentre Mario y no requiere pulsar ninguna tecla. Eso
si podremos mantener una de las teclas de dirección
pulsadas para controlar la caída.

Agachado: Este movimiento hará que Mario reduzca su
tamaño lo cual puede ser útil para esquivar una bala por
ejemplo. Mario pequeño no se podrá agachar. Para
alcanzar este estado se debe pulsar la tecla de dirección
que apunta hacia abajo (KEY_DOWN).
Cuando nos encontremos en este estado no se podrá
saltar.

Disparando: Este movimiento solo se podrá hacer
cuando se encuentre en el estado Mario Fuego. Para
realizarlo habrá que hacer una pulsación de la tecla de
correr (KEY_SPEED).

Herido: Este estado se alcanzará tras colisionar con
algún enemigo, acto seguido dispondrá de un tiempo de
aproximadamente medio segundo de inmunidad y luego
cambiara de estado.
En nuestra implementación distinguimos ente:

Avanzar: Esta acción consiste en correr hacia la
derecha, dicha acción tiene una prioridad muy baja, ya
que como es lógico será interrumpida cuando encuentre
un enemigo o tenga que saltar.
Esta es la acción básica de nuestro Agente.

Saltar paredes: Como su propio nombre indica esta
acción se aplicara cuando Mario encuentre un obstáculo
en su campo de visión. Las reglas que aplicamos para
este método son muy amplias debido a que deberá
distinguir entre una amplia gama de superficies y
también dependiendo de la superficie elegir la mas
optima Hemos incorporado un contador de saltos cuyo
objetivo es que cuando la tecla salto este mucho tiempo
pulsada pero siga teniendo que saltar suelta la tecla (se
ponga a KEY_JUMP=false en el código). Esto es muy
necesario debido a que Mario no puede saltar si ya esta
presionada la tecla de salto y si esto ocurriera antes de
que Mario pudiera saltar, si por ejemplo esta en el aire,
esto produciría que nuestro agente se quedase
bloqueado.

Saltar escaleras: Este movimiento es uno de los más
complicados debido a la complejidad que supone saltar
de un escalón en un escalón. Primero deberá detectar la
escalera, lo cual lo hacemos cuando se la encuentra o
cae de un salto en un escalón. A continuación saltará de
uno peldaño si ese es el último escalón, es decir, si
después ya solo tiene vacio saltara al otro lado, en caso
contrario deberá saltar al siguiente escalón. Esto lo
realizará todas las veces que sea necesario.

Saltar enemigo: Para esta acción hemos puesto reglas
genéricas aplicables a todos los enemigos, ya que
después de analizar el código que nos proporcionan
hemos visto que la mayoría tienen un valor mayor o
igual a 80. Estas reglas son del estilo: saltar cuando
detecte un enemigo delante suya, saltar cuando detecte
un enemigo cayendo hacia él, etc. Para hacer bien este
movimiento deberemos tener en cuenta muchas
variantes ya que los enemigos pueden perseguir a
Mario, caer del cielo, o incluso caer a sus “pies”.

Agacharse: Esto es un caso especial de esquivar un
enemigo y lo hacemos cuando un misil va hacia Mario,
en este caso se agacha hasta que pase. Para ello
mantenemos pulsada la tecla con dirección hacia abajo
(KEY_DOWN=true) e irá comprobando si en la
posición de encima de su cabeza no tiene nada, sólo
entonces podrá levantarse.

Retroceder: Si hay enemigos en una posición en la cual
no va a poder esquivarlos saltando, retrocedemos. Esto
se antoja de vital importancia en niveles muy altos
donde pueden aparecer 10 enemigos de golpe, esto hará
que retrocedamos y podamos analizar mejor la situación
ya que si hubiéramos seguido avanzando podríamos
haber sido heridos al no poder tener en cuenta todos a la
vez.
Si el estado inicial era Mario Fire pasará a Supe Mario,
si por el contrario Mario se encontraba en el estado de
Supe Mario iremos a Mario Pequeño y por último si
estábamos en Mario Pequeño moriremos y se acabará la
partida.
4.5 Movimientos de nuestro agente
Nuestro agente como ya mencionamos en el apartado de
algoritmos será reactivo y se basara en distintas reglas de más o
menos prioridad para decidir qué acción deberá realizar.
Para ilustrar gráficamente los movimientos hemos construido un
árbol para que se pueda ver el nivel de decisión el primer estado
que es Final especial es el estado que tiene más prioridad y el
estado Avanzar es el que tiene menos prioridad.
INICIO:
Final
especial
Esquivar
flor
Esquivar
bala
Saltar
tubería/cañ
ón
Saltar
escalera
Evitar
hoyos
Saltar pared
Avanzar

Andar sobre tubo: Cuando estamos sobre un tubo no
corremos, esto evitará que nos caigamos en un hoyo o
justo al lado de un enemigo al caer. Para esto último
deberemos hacer varías consideraciones ya que habrá
que explorar diferentes opciones y añadir muchas
reglas debido a la posible diversidad del escenario.

Escalón antes de hoyo: Cuando detectamos un escalón
antes de un hoyo calculamos si podemos realizar el
salto, si es afirmativo saltamos y si no vamos más
despacio. El ir más despacio tiene como objetivo poder
caer en el siguiente escalón y una vez allí poder afrontar
el salto con seguridad.

Final En Alto Para poder terminar una partida cuando el
final es un alto que no es accesible a priori hemos hecho
una serie de métodos que son: SaltoFinal, Doble,
EstoyDebajo y buscarCamino por los que ira pasando
para poder llegar a la meta.
Algunos de los más usuales son:
4.6 Interfaz Gráfico
Para empezar cabe el interfaz gráfico se facilita en [8]. Este
interfaz es bastante completo y a parte de unos gráficos
aceptables, nos da multitud de opciones para poder cambiar de
nivel, apariencia, obstáculos…
Vamos a mostrar una captura de la pantalla para que se pueda
tener una idea más gráfica.
Nuestro agente dispondrá de dos matrices de 19x19 las cuales le
aportarán información de su entorno. Mario estará en la posición
(9,9) en todo momento.
En cualquiera de las dos matrices si no hay nada, esa posición
tendrá el valor 0.
La primera matriz será LevelScene, esta matriz le indicara los
elementos fijos de la pantalla, tales como: paredes, tuberías,
cañones…
Como podemos apreciar en esta primera matriz salen todos los
valores del entorno incluyendo las monedas cuyo valor es el único
positivo (el 1).
La segunda matriz es enemies también de 19x19 y en su interior
tendrá los valores de los enemigos.
Algunos de los enemigos más usuales son:
Una vez tenemos identificados los números que tendrá la matriz
enemies, vamos a ver sobre la pantalla como quedaría.
También es llamativo resaltar que la mayoría de enemigos tiene
un valor superior a 80, eso nos facilitara a la hora de implementar
el código para que esquive a cualquier enemigo desconocido y sin
que necesidad de tratarlo como un caso especial.
Para eso utilizamos la pantalla anterior aunque solo tengamos un
par de enemigos del mismo tipo.
Como podemos ver en la imagen aunque el fuego que arroja
Mario no es un enemigo como tal, también viene indicada en la
matriz enemies con un 25.
Como hemos podido comprobar estas matrices nos van a ser de
vital importancia para poner las reglas ya que nos irán
proporcionando información detallada de la posición y el numero
de enemigos en cada instante.
5. SOLUCIÓN ÓPTIMA
Obviamente el algoritmo que hemos implementado en dos
semanas dista de ser el óptimo y deseado, la mayoría de los
participantes mejor clasificados disponen de algoritmos genéticos
Y en particular los tres mejores clasificados del 2010 usaron el
pathfinding A*
6. BIBLIOGRAFÍA
[1] http://es.wikipedia.org/wiki/%C3%81rbol_de_decisi%C3%B
3n
[2] http://julian.togelius.com/mariocompetition2009/GIC2009Co
mpetition.pdf
[3] http://es.wikipedia.org/wiki/Algoritmos_gen%C3%A9ticos
[4] http://eddyalfaro.galeon.com/geneticos.html
[5] http://es.wikipedia.org/wiki/Algoritmo_de_b%C3%BAsqued
a_A*.
[6] http://es.wikipedia.org/wiki/Agente_inteligente_(inteligencia
_artificial)
[7] http://www.ati.es/novatica/2000/145/vjulia-145.pdf
[8] http://www.marioai.com/
Descargar