Tres en raya

Autores:

  • Javier Vilches Colombás
  • Diego González Rodríguez
  • Bogdan Ionut Maran

Introducción

En esta memoria explicaremos todo lo necesario para saber cómo hemos realizado nuestro proyecto, el clásico juego de 3 en raya. Nos decidimos por hacer este proyecto, porque nos pareció algo bastante interesante el hacer un juego interactivo al que pudieran jugar 2 personas. Nos topamos con distintos problemas y complicaciones tanto hardware como software al hacer el proyecto, pero esto es algo que explicaremos más adelante. El reparto de tareas ha sido más o menos equitativo, ya que hemos quedado los 3 integrantes del grupo siempre en algún sitio y hemos avanzado en conjunto.

Materiales utilizados

Los componentes y materiales que hemos empleado a la hora de hacer este proyecto han sido los siguientes:

  • 9 LEDs RGB (6€)
  • 2 Pulsadores
  • 1 Protoboard
  • 1 Board del módulo de expansión
  • 1 Arduino UNO
  • Cableado macho-macho
  • Resistencias
  • Caja de cartón
  • Spray de pintura (2€)
  • Cinta aislante (2€)

Código

const int blanco    = 0;
const int azul     = 1;
const int rojo      = 2;
const int ultimoled   = 9;        
const int parpadeo      = 1;        
const int off       = 0;      
const int victoriasPosibles[9]  = {8,123,456,789,147,258,369,159,357};    




int tardar         = 200;  
int pinled[10]      = {0,12,2,3,4,5,6,7,8,9};
int pinRojo     = 10;  
int pinAzul    = 11;  
int botonSelec    = 0;    
int botonSig  = 1;    
int color           = azul;  
int ultcolor        = rojo;
int led             = 1;      
int L[10]           = {0,0,0,0,0,0,0,0,0,0};  
int B[10]           = {0,0,0,0,0,0,0,0,0,0};  
int P[10]           = {0,0,0,0,0,0,0,0,0,0};    
int ledjugada[4]    = {0,0,0,0};    
unsigned long tiempo;        
boolean encendido   = true;      
boolean victoria  = false;




void resetearLeds() {  
 
  for (int i=1;i<=9;i++) {
    pinMode(pinled[i],OUTPUT);
    digitalWrite(pinled[i], HIGH);
  }
 
  pinMode(pinRojo,OUTPUT);
  pinMode(pinAzul,OUTPUT);
  digitalWrite(pinRojo,LOW);
  digitalWrite(pinAzul,LOW);
 
}






void corrienteLed(int color) {
  if (color == azul) {
    digitalWrite(pinRojo,LOW);
    digitalWrite(pinAzul,HIGH);
  }
  if (color == rojo) {
    digitalWrite(pinAzul,LOW);
    digitalWrite(pinRojo,HIGH);
  }
}


void encenderLed(int led,int color) {
  corrienteLed(color);
  digitalWrite(pinled[led],LOW);      
}


void apagarLed(int led) {            
  digitalWrite(pinled[led],HIGH);    
}


void mostrarLeds(int arrayleds[])  {
  for (int i=1;i<=9;i++) {
    if (arrayleds[i] != off) {
      encenderLed(i,arrayleds[i]);
      delay(1);    
      apagarLed(i);
    }
    else apagarLed(i);
  }
}


void parpadearLeds(int intervalo) {  
  if (millis() - tiempo > intervalo) {        
    if (encendido == true)  encendido = false;
    else encendido = true;
    tiempo = millis();
  }
  for (int i=1;i<=9;i++) L[i]=P[i];    
  for (int i=1;i<=9;i++)          
    if (B[i] == parpadeo) {      
      if (encendido)  L[i] = P[i];    
      else L[i] = off;
    }
  mostrarLeds(L);                      
}


int cambioDeColor(int param_color) {  
  switch (param_color) {
    case azul: return rojo;
    case rojo:  return azul;
    default:    return blanco;    
  }
}


int avanzaLed(int index) {  
  for (int i=index;i<=9;i++)
    if (P[i] == off) return i;
  for (int i=1;i<=index;i++)
    if (P[i] == off) return i;
  return 0;
}




void parpadeoVictoria(int numjugada) {
    for (int i=0;i<=9;i++) B[i] = off;  
    B[ledjugada[1]] = parpadeo;                                      
    B[ledjugada[2]] = parpadeo;
    B[ledjugada[3]] = parpadeo;
}


boolean hayVictoria(int numjugada, int turno, int arraycontrol[]) {  
  for (int i=0;i<=3;i++) ledjugada[i] = 0;                              
  ledjugada[1]  = numjugada/100;                    
  ledjugada[2]  = (numjugada - 100*ledjugada[1])/10;  
  ledjugada[3]  = numjugada - 100*ledjugada[1] - 10*ledjugada[2];              
  if (     (arraycontrol[ledjugada[1]] == turno)
        && (arraycontrol[ledjugada[2]] == turno)
        && (arraycontrol[ledjugada[3]] == turno)  )  return true;        
  return false;  
}


boolean tresenraya(int turno, int arraycontrol[]) {  
  boolean tres = false;                        
  for (int i=1;i<=victoriasPosibles[0];i++)                        
    if (  hayVictoria(victoriasPosibles[i],turno,arraycontrol) )  {      
      parpadeoVictoria(victoriasPosibles[i]);                                        
      tres = true;                                                            
    }
  return tres;                                                              
}








void setup() {


  Serial.begin(9600); //Útil para la depuración
 
  resetearLeds();
 
  for (int i=1;i<=ultimoled;i++) L[i] = 1;
  tiempo = millis();    
  while (millis() - tiempo < tardar) {
    mostrarLeds(L);
  }
  for (int i=1;i<=ultimoled;i++) apagarLed(i);
  delay(tardar);
  for (int i=1;i<=ultimoled;i++) L[i] = 2;  
  tiempo = millis();  
  while (millis() - tiempo < tardar) {
    mostrarLeds(L);
  }
  for (int i=1;i<=ultimoled;i++) apagarLed(i);
  delay(tardar);
}




void loop() {
 
  for (int i=0;i<=3;i++) ledjugada[i] = 0;
  for (int i=0;i<=9;i++) {
    L[i] = off;
    B[i] = off;  
    P[i] = blanco;
  }  
  tardar     = 200;
  led         = 1;
  encendido   = true;
  victoria  = false;
 
 
  while ( (victoria != true) && (9-P[0]!=0) ) {
      P[0] = P[0] + 1;                                              
      if (P[0] != 1) color = cambioDeColor(color);                      
      else {                                                    
        color    = cambioDeColor(ultcolor);
        ultcolor = color;
      }
      L[led] = color;                                                    
      while ( analogRead(botonSelec) == off )  {              
          tiempo = millis();                                              
          B[led] = parpadeo;                                            
          P[led] = color;
          while ( (analogRead(botonSig) == off) && (analogRead(botonSelec) == off) )  parpadearLeds(2*tardar);
          P[led] = blanco;
          for (int i=1;i<=9;i++) {                                      
            L[i] = P[i];                                                
            B[i] = off;                                                  
          }
          if (analogRead(botonSelec) != off) {                          
            while ( analogRead(botonSelec) != off ) mostrarLeds(L);  
            P[led] = color;                                              
            for (int i=1;i<=9;i++) L[i] = P[i];                        
            break;                                    
          }
          while ( analogRead(botonSig) != off ) mostrarLeds(L);  
          for (int i=1;i<=9;i++) L[i] = P[i];                            
          if (led == 9) led = avanzaLed(1);                              
          else led = avanzaLed(led+1);
      }
      led = avanzaLed(1);                                                
      victoria = tresenraya(color,P);                                
                                 
  } 
 
 
                                 
  tiempo = millis();                                                  
  while ( (analogRead(botonSig) == off) && (analogRead(botonSelec) == off) )  parpadearLeds(tardar/2);  
  while ( (analogRead(botonSig) != off) || (analogRead(botonSelec) != off) )  parpadearLeds(tardar/2);  
}  

Problemas y soluciones

Como hemos mencionado anteriormente, nos topamos con muchísimos problemas a la hora de hacer el proyecto. Empezaremos por los problemas de hardware que tuvimos. 

Un problemas que tuvimos, fue que al ser un tres en raya, necesitábamos cierta separación entre los LEDs, para que fueran distinguibles fácilmente, y no nos fue posible lograr esta distancia teniendo solamente 1 Protoboard, ya que entre los LEDs, el cableado y las resistencias, no quedaba bien. La solución que encontramos a este problema estaba más cerca de lo que pensábamos, de hecho, estaba en la propia caja con los materiales, en la que había una board de expansión, que aunque era muy pequeña, nos sirvió perfectamente para lograr la separación mínima que queríamos.

Otro problema bastante tedioso que realmente no supimos por qué ocurría, fueron las resistencias. Las resistencias que pusimos a los pulsadores, nos daban problemas de vez en cuando y no sabíamos la razón. A veces era como que dejaban de funcionar y nuestro circuito se volvía loco y los LEDs o se volvían locos y no seguían ningún tipo de patrón o directamente se apagaban. Esto lo resolvimos intercambiando los pines de las resistencias, es decir, colocándolas al revés, lo cual no tiene ningún sentido aparente, pero funcionó.

Un problema bastante fácil de resolver fue que conectamos mal algunos de los LEDs RGB, ya que no nos dimos cuenta de que había que conectarlos de una manera determinada porque sus pines correspondía cada uno con un color y con tierra. Simplemente miramos cómo había que conectarlos bien y arreglamos el problema.

Al principio, teníamos pensado hacer otro proyecto, que era un 4 en raya, y lo queríamos hacer con una matriz LED. Compramos varios materiales que íbamos a necesitar y cuando nos fuimos a poner con el proyecto nos dimos cuenta de que iba a suponer un gasto muy elevado en cuanto a materiales, porque íbamos a necesitar otra Protoboard, muchos más cables, etc. y aparte de todo esto, no nos alcanzaban los pines del Arduino UNO.

En cuanto a problemas software, uno bastante grande que tuvimos fue como simular el algoritmo de victoria para el tres en raya. Buscando por internet y viendo varios vídeos, nos dimos cuenta de que era más sencillo de lo que creíamos, y simplemente escribimos las 8 combinaciones ganadoras, y cuando los 3 LEDs de cada combinación se iluminaran del mismo color, daba victoria.

Otro problema que tuvimos con respecto al código fue que no pudimos simular el empate técnico en el 3 en raya. Lo que queremos decir con esto es que el propio juego detecte cuándo es imposible que ninguno de los 2 jugadores gane sin haber completado todas las posiciones del tablero. Esto suponía una complejidad muy grande, ya que no teníamos ni idea de cómo hacerlo y al buscar tutoriales por internet nos dimos cuenta de que era algo muy complicado, que no entendíamos muy bien y que además no sabíamos exactamente cómo implementar en el código que nosotros teníamos.

También tuvimos problemas con la función “delay()”, y decidimos usar “millis()”. Esta nos dio también fallos pues habíamos definido una variable int para guardar su valor y el programa se nos cerraba o no funcionaba correctamente. Después vimos que debíamos declarar esa variable tiempo como un unsigned long, y a partir de ahí no volvimos a tener problemas.

Posibles mejoras

Algunas posibles mejoras que podríamos añadir son las de implementar el algoritmo de empate, para que los jugadores no pierdan tiempo rellenando todas las casillas cuando va a ser imposible que ninguno de los 2 gane.

Una mejora hardware que implementaríamos para que el juego fuera más atractivo y llamativo visualmente sería cambiar los LEDs RGB por una matriz LED RGB ya sea de 8×8 o de 16×16 y hacer cada posición del tablero más grande.

Por último, podríamos hacer que el juego que hemos diseñado fuera portátil, conectándolo a una pila, pero por razones de espacio en la caja que escogimos para montarlo, nos era imposible, aunque sería algo bastante sencillo de implementar, ya que con la pila de 9V que teníamos hubiese funcionado correctamente.

También te podría gustar...

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *