¿Qué está haciendo mi adversario?
En una partida de CodedArena, saber en todo momento qué está haciendo el adversario de vuestro personaje es clave para la victoria.

Atención: Contenido visualmente obsoleto. Contiene imágenes y reproducciones animadas de CodedArena 1.0.
Este artículo está en proceso de revisión para adaptarlo a la apariencia visual de CodedArena 2.0.
Una de las variables de los personajes menos utilizada, y en cambio una de las más útiles, es action_name.
¿Qué es action_name, y para qué sirve?
Ahora lo veremos, con algunas de sus posibles aplicaciones.
Saber qué hace otro personaje
La variable action_name, nos permite saber qué acción está realizando en un determinado momento otro personaje, adversario o aliado.
Esta variable contiene una cadena, en concreto el nombre de la acción que se está llevando a cabo.
Por ejemplo, si un adversario está invocando:
return ["cast", "incinerate", target]
cuando consultemos la variable action_name, encontraremos la cadena incinerate.
Un ejemplo de código
Veamos el siguiente ejemplo:
target = None
for mob in mobs:
if mob.name != self.name:
target = mob
break
if target.action_name == "nothing" or len(target.action_name) == 0:
return "No action!"
else:
return target.action_name
Si vais a Escaramuzas con vuestro personaje, y probáis este código, pasaran partidas como la que se ve a continuación.

Como habéis visto, nuestro personaje ha estado diciendo constantemente la acción del adversario, ¡si este estaba realizando alguna!
Si un personaje está realizando una acción que no se puede interrumpir, como por ejemplo Move, la variable action_name puede contener la cadena "nothing"
o la cadena vacía ""
.
¿Y qué utilidades puede tener?
¡Muchas!¡Todo aquello que os permita entender qué hace otro personaje, y reaccionar en consecuencia!
Pongamos algunos ejemplos, y vamos viéndolos uno a uno.
Interrumpir un hechizo
Hay hechizos que, con una probabilidad u otra, pueden llegar a interrumpir, cegar y/o silenciar a nuestro adversario, como es el caso de Holy Splash, Blind o Interrupt.
Y también sabemos que hay hechizos con los que pueden atacar a nuestro personaje que son más dañinos que otros.
Así pues, si tuvieseis que utilizar un hechizo de interrupción, ¿lo harías en cualquier momento, o lo reservaríais para interrumpir un hechizo determinado del adversario?
He aquí una de las posibilidades de utilizar action_name y saber qué hace nuestro adversario.
Veamos un ejemplo:
target = None
for mob in mobs:
if mob.name != self.name:
target = mob
break
x = "none"
y = "none"
if self.x > target.x:
x = "left"
elif self.x < target.x:
x = "right"
if self.y > target.y:
y = "up"
elif self.y < target.y:
y = "down"
if self.max_distance_of("holy splash") < self.distance_to(target):
return ["move", x, y]
if target.action_name == "nothing" or len(target.action_name) == 0:
return "No action!"
else:
if target.action_name == "incinerate":
if self.is_ready("holy splash"):
return ["cast", "holy splash", target]
else:
return target.action_name
Nuestro código ha cambiado un poco, pero no mucho. Hemos añadido algo de código para poner a nuestro personaje siempre a distancia de lanzamiento de Holy Splash, y por otro lado si nuestro personaje detecta que el adversario está invocando Incinerate, contraatacará invocando Holy Splash, con la esperanza de cegar al adversario (¡tra cosa es que ocurra!).
Como podéis ver en la siguiente animación, cada vez que nuestro adversario trata de invocar Incinerate, nuestro personaje ya no lo dice, sino que invoca Holy Splash:

Saber qué tipo de adversario tienes delante
Otra de las posibilidades son saber qué tipo de adversario tienes delante, cómo lucha, qué tipo de hechizos lanza, y actuar en consecuencia.
¿Es un mago cuerpo a cuerpo, a distancia, de DoTs (Damage over Time) como Incenerate o Corruption?
Si sabemos qué hace el adversario, podemos establecer una estrategia u otra para nuestro personaje.
¡Veamos un ejemplo! (es largo, pero ten paciencia, ¡es muy útil!)
# Inicializamos variables
target = None
ranged_spells = ["incinerate", "corruption"]
melee_spells = ["slam", "rend"]
# Creamos las variables de la memoria del personaje que necesitamos para contar
if "last_spell" not in self.memory:
self.memory["last_spell"] = None
self.memory["ranged_spells_count"] = 0
self.memory["melee_spells_count"] = 0
self.memory["other_spells_count"] = 0
for mob in mobs:
if mob.name != self.name:
target = mob
break
if target.action_name == "nothing" or len(target.action_name) == 0:
self.memory["last_spell"] = None
return "No action!"
else:
# Como el adversario está invocando un hechizo, recuperamos los contadores
last_spell = self.memory["last_spell"]
ranged_spells_count = self.memory["ranged_spells_count"]
melee_spells_count = self.memory["melee_spells_count"]
other_spells_count = self.memory["other_spells_count"]
# Miramos si el adversario ha empezado a invocar un hechizo, o lleva un rato haciéndolo
if last_spell is None:
# Como ha empezado a invocar un nuevo hechizo, lo almacenamos para no volver a incrementar los contadores mientras dura la invocación
self.memory["last_spell"] = target.action_name
# Comprobamos de qué tipo de hechizo se trata, y aumentamos el correspondiente contador
if target.action_name in ranged_spells:
ranged_spells_count = ranged_spells_count + 1
elif target.action_name in melee_spells:
melee_spells_count = melee_spells_count + 1
else:
other_spells_count = other_spells_count + 1
# Actualizamos la memoria de nuestro personaje con los nuevos contadores
self.memory["ranged_spells_count"] = ranged_spells_count
self.memory["melee_spells_count"] = melee_spells_count
self.memory["other_spells_count"] = other_spells_count
# Volcamos los contadores a la consola de Actividad
self.debug("Ranged: " + str(ranged_spells_count))
self.debug("Melee: " + str(melee_spells_count))
self.debug("Other: " + str(other_spells_count))
return target.action_name
Vamos a explicar paso a paso la estrategia.
Contadores en la memoria del personaje
Como podemos ver en el código anterior, hemos utilizado la memoria de nuestro personaje para almacenar el número de veces que se lanza un hechizo de distancia, las veces que se lanza uno cuerpo a cuerpo, y los otros tipos de hechizos, como Speed.
self.memory["last_spell"] = None
self.memory["ranged_spells_count"] = 0
self.memory["melee_spells_count"] = 0
self.memory["other_spells_count"] = 0
Además, tenemos otra variable en la memoria, last_spell
, que nos ayudará a saber cuando ha empezado a invocar un hechizo el adversario, y por lo tanto incrementar los contadores, y cuando lleva un rato invocando el mismo hechizo, para no incrementar los contadores, porque ya lo hicimos.
Incrementando los contadores
Si detectamos, gracias a que self.memory["last_spell"]
tiene el valor None
, que nuestro adversario empieza a lanzar un hechizo, en primer lugar almacenamo su nombre en la memoria:
self.memory["last_spell"] = target.action_name
Así evitaremos en el siguiente ciclo de consulta a nuestro personaje, donde el adversario seguirá invocando el mismo hechizo, volver a incrementar los contadores, gracias al condicional anterior:
if last_spell is None:
Miramos qué tipo de hechizo es, buscándolo en las listas ranged_spells
y melee_spells
, encrementamos el correspondiente contador:
if target.action_name in ranged_spells:
ranged_spells_count = ranged_spells_count + 1
elif target.action_name in melee_spells:
melee_spells_count = melee_spells_count + 1
else:
other_spells_count = other_spells_count + 1
Actualizando los contadores en la memoria
Cuando tengamos los contadores actualizados, actualizamos la memoria:
self.memory["ranged_spells_count"] = ranged_spells_count
self.memory["melee_spells_count"] = melee_spells_count
self.memory["other_spells_count"] = other_spells_count
Volcando la información en la consola de Actividad
Finalmente, lo que nos queda es volcar los datos que queramos en la consola de Actividad, que a medida que nuestro adversario vaya invocando hechizos obtendremos datos:

Como podéis ver, a medida que nuestro adversario utiliza un hechizo u otro, los contadores que nuestro personaje tiene en memoria se van actualizando, y son volcados a la consola de Actividad mediante la función self.debug()
.
Muchas más opciones, solo imagínatelas
CodedArena y Python son herramientas con las que ejercitar vuestra creatividad. Una vez entedáis las herramientas, sólo se trata de pensar en fórmulas que os resulten útiles.
Si consideráis que hay una opción interesante que, mezclando la memoria del personaje con datos extraídos de los personajes, o con cualquier otra herramienta que os ofrezca CodedArena, no dudéis en programar y probar, y no tengáis miedo a equivocaros, porque así mejoraréis. Depurad, analizad el flujo del programa, entended qué ha funcionado y qué no, y así conseguiréis estrategias y algoritmos increíbles.
¡Solo tenéis que imaginarlo, y hacerlo posible!
¡Adelante!