Una forma de acceder común, y peligrosa

Es muy habitual ver códigos Python de personajes de CodedArena que, para trabajar con los diferentes personajes de una misión, crean código similar al que vemos a continuación.

enemy = mobs[1]

if self.is_ready("slam") and self.mana >= self.cost_of("slam"):
    return ["cast", "slam", enemy]

o en su versión más resumida:

if self.is_ready("slam") and self.mana >= self.cost_of("slam"):
    return ["cast", "slam", mobs[1]]

Acceder de esta forma a los elementos de la lista mobs es un error, y veremos ahora porqué.

La lista mobs en CodedArena

Como ya sabéis, en la lista mobs el videojuego informa a vuestro personaje de todos los personajes que se encuentan en la escena de la misión, incluyendo el vuestro.

En las misiones de la Campaña 1, en general hay pocos personajes, y vuestro personaje siempre ocupa la primera posición de la lista, mobs[0]. Ésto es así porque el objetivo de la Campaña 1 es aprender las bases de la programación.

Sin embargo, en las misiones de la Campaña 2, y en las Competiciones, pueden pasar dos cosas que afectan a la lista mobs:

  • el videojuego puede llegar a mezclar los elementos de la lista, de forma aleatoria, en cada ciclo de ejecución
  • si un adversario es eliminado, puede llegar, en algunos casos, a ser eliminado de la lista mobs

¿Y en qué afecta a vuestro código? Veamos un ejemplo.

El desastre

Trabajemos con el código que hemos visto al principio:

if self.is_ready("slam") and self.mana >= self.cost_of("slam"):
    return ["cast", "slam", mobs[1]]

Esta fórmula funcionará perfecta si en ese momento la lista mobs que nos ha pasado el videojuego tiene la siguiente apariencia:

mobs = [self, npc1]

donde npc es, por ejemplo, un Dark Elemental. Pero, ¿y si en el siguiente ciclo de ejecución el videojuego le pasa a tu personaje la siguiente lista?

mobs = [npc1, self]

¿Qué pasará entonces? ¿A quién atacará tu personaje con el hechizo Slam? En efecto, ¡a sí mismo!

Otro desastre

Imaginemos el siguiente código:

enemy1 = mobs[1]
enemy2 = mobs[2]

if .....

Mientras en la escena haya 3 personajes, por lo menos, no habrá problemas. Pero, ¿qué pasará si, por motivos de la partida, en la escena sólo quedan vuestro personaje y otro más? ¿Cuántos elementos tendrá la lista mobs?

El código anterior nos dará un error list index out of range, es decir, un error donde nos indica que ha tratado de acceder a un índice de la lista más allá de su longitud.

La solución: iteradores y condicionales

La solución pasa por no trabajar con las posiciones fijas de la lista, y buscar a los diferentes personajes utilizando el iterador for y los condicionales if/elif/else.

Veamos un ejemplo, basado en el código del inicio de este artículo.

enemy = None

for mob in mobs:
    if mob.name != self.name:
        enemy = mob
        break

if self.is_ready("slam") and self.mana >= self.cost_of("slam"):
    return ["cast", "slam", enemy]

Con este código, ya no nos importa si el adversario se encuentra en mobs[0]o mobs[7], porque lo vamos a encontrar con la ayuda de la lógica, comparando en este caso su nombre con el nombre de nuestro personaje.

Otro ejemplo:

enemy = None

for mob in mobs:
    if mob.name.lower() == "dark elemental 1":
        enemy = mob
        break

if self.is_ready("slam") and self.mana >= self.cost_of("slam"):
    return ["cast", "slam", enemy]

Aquí buscaríamos a un adversario por su nombre en concreto, si lo sabemos. De esta forma, sigue sin importar que posición ocupa en la lista mobs.

Conclusiones

  • En la medida de lo posible, evitar las posiciones fijas de las listas, a menos que no haya otra opción.
  • Usad iteradores, condicionales y la lógica. Son ideales para analizar el contenido de las listas.
  • A medida que avancéis en las Campañas de CodedArena, las misiones no sólo se complican, si no que además el videojuego irá poniendo trabas para que vuestros algoritmos deban enfrentarse a mayores desafios. ¡No todo es Campaña 1!