Inicio >> Proyectos >> El juego de Simón con Arduino >> Parte 2


En la parte 1 del proyecto vimos cómo hacer todas las conexiones y cómo configurar los pines digitales necesarios en el Arduino. Vamos a continuar completando el sketch, así que si no lo tienes vuelve a la parte 1 y complétala antes de seguir.

En esta segunda parte vamos a programar las rondas y las secuencias que harán los LEDS.

Te recuerdo cómo funciona el juego de Simón para que tengas claro lo que vamos a programar.

El juego genera secuencias de luces aleatorias para que el usuario las repita. Cada partida tiene varias rondas y en cada ronda la secuencia se alarga. En la primera ronda se ilumina solo una luz (en nuestro caso un LED) de forma aleatoria. En la siguiente ronda se ilumina la luz anterior y otra nueva también aleatoria. En la siguiente ronda se repiten las dos luces anteriores más otra nueva aleatoria y así sucesivamente hasta que el juego termina después de x rondas.

En el juego completo el usuario tiene que repetir la secuencia de luces pulsando los botones después de cada ronda, pero eso lo haremos en la siguiente parte. En esta segunda parte del proyecto nos vamos a centrar solo en las secuencias de luces que se generan en cada ronda.

Declaraciones

Tenemos que añadir nuevas declaraciones al sketch que ya teníamos:

const int ROUNDS = 20;
int sequence[ROUNDS];
int n = 0;

La constante entera ROUNDS es el número de rondas que se deben jugar para ganar el juego. He puesto 20, pero puedes poner las que quieras.

También vamos a necesitar un array, que he llamado sequence, del tamaño de la constante ROUNDS. Aquí guardaremos valores aleatorios comprendidos entre 0 y 3, es decir, las posiciones del array LEDS (que declaramos en la parte 1). Es la secuencia que debe repetir el usuario para ganar.

La variable entera n nos servirá para controlar la ronda en la que va el usuario. Como ya comenté antes, en la primera ronda se iluminará solo un LED, en la siguiente se iluminará otro más y así sucesivamente hasta mostrar la secuencia completa, por tanto n servirá para limitar el número de elementos del array sequence que se van a usar. En la primera ronda n tendrá valor 1, en la segunda tendrá valor 2, etc.

En cuanto a las declaraciones nada más.

Vamos con la configuración.

Configuración

Dentro de la función setup() vamos a añadir esta instrucción:

randomSeed(analogRead(0));

Es lo que comúnmente se conoce como semilla. Sirve para inicializar el generador de números aleatorios que utilizaremos posteriormente para generar la secuencia. Esto nos garantiza que cada vez el número generado sea diferente.

Funciones

Vamos a declarar 3 nuevas funciones que nos van a permitir controlar los LEDs.

Veamos una por una.

Función printLed

La función printLed recibe como parámetro el pin digital de un LED e ilumina ese LED durante un segundo (1000 ms). 

void printLed(int led){
  digitalWrite(led, HIGH);
  delay(1000);
  digitalWrite(led, LOW);
}

Función randomSequence

La función randomSequence genera una secuencia aleatoria y la guarda en el array sequence.

Genera tantos valores aleatorios como rondas totales tenga el juego, es decir, el valor de ROUND.

void randomSequence(){
  for (int i=0; i<ROUNDS; i++){
    sequence[i] = random(0,SIZE);
  }
  n = 1;  
}

La instrucción random(0, SIZE) es la encargada de generar el número aleatorio. Será cada vez diferente pero siempre comprendido entre 0 (incluido) y SIZE (excluido). Recuerda que SIZE tiene valor 4, por lo que los valores generados serán 0, 1, 2 o 3. Esto es así porque el array de LEDs tiene 4 posiciones (0: verde, 1: rojo, 2: azul y 3:amarillo).

También inicializamos la variable n a 1 para que el juego comience en la primera ronda. En cada ronda esta variable se irá incrementando, pero eso lo veremos más adelante.

Función printSequence

La función printSequence es la encargada de mostrar la secuencia iluminando y apagando los LEDS correspondientes, es decir, los indicados en el array sequence:

void printSequence(){
  delay(1000);
  for(int i=0; i<n; i++){
    printLed(LEDS[sequence[i]]);
    Serial.println(sequence[i]);
    delay(1000);
  }
}

Fijate que el bucle for solo llega hasta n, que es el número de ronda que se está jugando. No queremos que se ilumine la secuencia entera, solo los n primeros correspondientes a la ronda.

Recuerda que los pines digitales de los LEDS están almacenados en el array LEDS. Usando sequence[i] obtenemos uno de los aleatorios generados anteriormente (un valor entre 0 y 3), es decir, una posición válida del array LEDS. Al pasar LEDS[sequence[i]] a la función printLed, se iluminará durante 1 segundo el LED que esté en dicha posición.

Prueba

Puedes probar el código llamando a las funciones desde la función principal (loop) de esta forma, pero no olvides completar el sketch con lo que vimos en la parte 1, sino no funcionará:

void loop(){
  Serial.println("Nueva secuencia: ");
  randomSequence();
  n=5;
  printSequence();
}

Le he dado valor 5 a la variable n para hacer una prueba. Como n es el número de ronda en la que estamos, puedes ir cambiando el valor para hacer distintas pruebas y comprobar cuántos LEDS se iluminan y qué secuencias de colores se generan.

Por si te quedan dudas de cómo añadir este nuevo código al anterior te dejo aquí el sketch completo con los nuevos cambios:

/*----------------------*
*     DECLARACIONES     *
*-----------------------*/
 
//LEDs:
const int LED_GREEN = 8;
const int LED_RED = 6;
const int LED_BLUE = 4;
const int LED_YELLOW = 2;
 
//pulsadores:
const int BTN_GREEN = 9;
const int BTN_RED = 7;
const int BTN_BLUE = 5;
const int BTN_YELLOW = 3;
 
//arrays:
const int LEDS[] = {LED_GREEN, LED_RED, LED_BLUE, LED_YELLOW};
const int BUTTONS[] = {BTN_GREEN, BTN_RED, BTN_BLUE, BTN_YELLOW};
const int SIZE = 4;
 
//indices:
const int GREEN = 0;
const int RED = 1;
const int BLUE = 2;
const int YELLOW = 3;

//rondas y secuencias:
const int ROUNDS = 20;
int sequence[ROUNDS];
int n = 0; 
 
/*----------------------*
*     CONFIGURACIÓN     *
*-----------------------*/
void setup(){
  Serial.begin(9600);
 
  for(int i=0; i<SIZE; i++){
    pinMode(LEDS[i], OUTPUT);
    pinMode(BUTTONS[i], INPUT);
  } 

  randomSeed(analogRead(0));
}

/*----------------------*
*       FUNCIONES       *
*-----------------------*/
void printLed(int led){
  digitalWrite(led, HIGH);
  delay(1000);
  digitalWrite(led, LOW);
}

void randomSequence(){
  for (int i=0; i<ROUNDS; i++){
    sequence[i] = random(0,SIZE);
  }
  n = 1;  
}

void printSequence(){
  delay(1000);
  for(int i=0; i<n; i++){
    printLed(LEDS[sequence[i]]);
    Serial.println(sequence[i]);
    delay(1000);
  }
}

/*----------------------*
*          LOOP         *
*-----------------------*/
void loop(){
  Serial.println("Nueva secuencia: ");
  randomSequence();
  n=5;
  printSequence();
}

En la siguiente parte del proyecto veremos cómo gestionar los turnos del jugador y cómo comprobar si repite las secuencias de forma correcta con los pulsadores.