Control de flujo, condiciones y bucles para artistas

Condiciones múltiples

Hemos visto que podemos utilizar if y else para comprobar una condición y ejecutar un código u otro en caso de que se cumpla o no, sin embargo en algunas ocasiones vamos a necesitar lidiar con más de una condición, e ahí lo que se conoce como condiciones múltiples.

Volvamos al ejercicio de la lección anterior donde nuestro círculo se movía por la diagonal rebotando de un lado al otro:

12 - Condicion extendida/sketch.js

var circulo = { x: 0, y: 0, d: 1 }

function setup() {
  createCanvas(400, 400);
}

function draw() {
  background(220)
  // Pintamos el círculo
  fill(220, 0, 0)
  ellipse(circulo.x, circulo.y, 50, 50)
  // Movemos el círculo
  circulo.x += 2 * circulo.d
  circulo.y += 2 * circulo.d
  // Comprobamos si nos salimos del lienzo
  if (circulo.x > width) { circulo.d *= -1 }
  if (circulo.x < 0) { circulo.d *= -1 }
}

Ahora vamos a trazar tres líneas horizontales cortando el lienzo, una a 100 píxeles de altura, otra a 200 y otra 300. Lo haremos justo después de pintar el fondo:

function draw() {
  background(220)
  // Pintamos el círculo
  fill(220, 0, 0)
  // Dibujamos tres líneas horizontales
  line(0, 100, width, 100)
  line(0, 200, width, 200)
  line(0, 300, width, 300)
  // ...
}

Estas tres líneas las vamos a usar como una guía porque nuestro siguiente objetivo será pintar la figura de un color diferente dependiendo de en qué parte se encuentre:

  • Si se encuentra en la primera parte, de 0 a 100 píxeles de altura, la figura será amarilla.
  • Si se encuentra en la segunda parte, de 100 a 200 píxeles de altura, la figura será roja.
  • Si se encuentra en la tercera parte, de 200 a 300 píxeles de altura, la figura será verde.
  • Si se encuentra en la segunda parte, de 300 a 400 píxeles de altura, la figura será azul.

Como podéis suponer cuatro posibilidades implican cuatro condiciones. Podríamos intentar hacerlo con lo que sabemos hasta ahora sobreescribiendo unas propiedades del círculo r, g, b y ajustando los colores en cada caso:

var circulo = { 
  x: 0, y: 0, d: 1, 
  r: 0, g: 0, b: 0 
}

// ...

function draw() {
  // ...
  
  // Dibujamos tres líneas horizontales
  line(0, 100, width, 100)
  line(0, 200, width, 200)
  line(0, 300, width, 300)
  // Pintamos el círculo
  if (circulo.y > 0) { 
    circulo.r = 220
    circulo.g = 220
    circulo.b = 0
  } 
  if (circulo.y > 100) { 
    circulo.r = 220
    circulo.g = 0
    circulo.b = 0
  } 
  if (circulo.y > 200) { 
    circulo.r = 0
    circulo.g = 220
    circulo.b = 0
  } 
  if (circulo.y > 300) { 
    circulo.r = 0
    circulo.g = 0
    circulo.b = 220
  } 
  fill(circulo.r, circulo.g, circulo.b) 
  // ...
}

Es una forma de hacerlo, pero no es óptima, eso es porque estas condiciones no están relacionadas entre ellas. Es decir, se están ejecutando siempre todas sobreescribiendose unas a otras. Pensadlo por un momento, si el círculo se encuentra en un lugar cuya posición y es mayor que 300, eso significa que también es mayor que 0, mayor que 100 y mayor que 200. Si añadimos un print en las condiciones lo veremos:

if (circulo.y > 0) { 
  circulo.r = 220
  circulo.g = 220
  circulo.b = 0
  print("Primera parte")
} 
if (circulo.y > 100) { 
  circulo.r = 220
  circulo.g = 0
  circulo.b = 0
  print("Segunda parte")
} 
if (circulo.y > 200) { 
  circulo.r = 0
  circulo.g = 220
  circulo.b = 0
  print("Tercera parte")
} 
if (circulo.y > 300) { 
  circulo.r = 0
  circulo.g = 0
  circulo.b = 220
  print("Cuarta parte")
} 

Esto es un problema porque estamos ejecutando muchísimo código innecesariamente, pero no temáis porque lo podemos arreglar. Existe una instrucción condicional que sirve para vincular varias condiciones entre ellas y optimizar mucho el código, se trata del else if, en español si no si.

El bloque else if se puede utilizar múltiples veces entre un bloque if y un bloque else, aunque éste último no es obligatorio:

if (circulo.y > 0) { 
  circulo.r = 220
  circulo.g = 220
  circulo.b = 0
  print("Primera parte")
} else if (circulo.y > 100) { 
  circulo.r = 220
  circulo.g = 0
  circulo.b = 0
  print("Segunda parte")
}  else if (circulo.y > 200) { 
  circulo.r = 0
  circulo.g = 220
  circulo.b = 0
  print("Tercera parte")
} else if (circulo.y > 300) { 
  circulo.r = 0
  circulo.g = 0
  circulo.b = 220
  print("Cuarta parte")
} 

Al cambiar el código veremos que no funciona correctamente y eso tiene una explicación. Se debe a que cuando se ejecuta una de las condiciones los demás else if se descartan. De ahí que para utilizar esta estructura haya que desarrollar las condiciones de menos excluyente a más excluyente, justo al contrario de como lo tenemos.

Pensadlo detenidamente, la condición circulo.y > 0 excluye todas las demás, por tanto la primera que deberíamos comprobar es circulo.y > 300 porque esa no excluye las demás, ¿verdad? Luego la de circulo.y > 200, la de circulo.y > 100 y finalmente circulo.y > 0:

if (circulo.y > 300) { 
  circulo.r = 0
  circulo.g = 0
  circulo.b = 220
  print("Cuarta parte")
}  else if (circulo.y > 200) { 
  circulo.r = 0
  circulo.g = 220
  circulo.b = 0
  print("Tercera parte")
} else if (circulo.y > 100) { 
  circulo.r = 220
  circulo.g = 0
  circulo.b = 0
  print("Segunda parte")
} else if (circulo.y > 0) { 
  circulo.r = 220
  circulo.g = 220
  circulo.b = 0
  print("Primera parte")
}