SIMON

Dependencies:   mbed tsi_sensor

main.cpp

Committer:
gonzaloMS
Date:
2019-06-22
Revision:
1:6cb3e90ec4f3
Parent:
0:31131c8fdcfb

File content as of revision 1:6cb3e90ec4f3:

#include "mbed.h"

//Creo los estados
enum{MUESTRA,MUESTRA2,NO_MUESTRA,NO_MUESTRA2,NO_INGRESA,INGRESA,ESPERA,FIN,LEE,APAGA,AGUARDA};
//   |--------------------------------------|-----------------------------|-----------------|
//          GENERACIÓN DE SECUENCIA                 CONFIRMACIÓN              PULSADORES

//Defino la cantidad máxima de elementos
const int MaxElem=24;

//Defino como salidas el led RGB en los tres colores, Red, Green y Blue
DigitalOut ledR(LED1);
DigitalOut ledG(LED2);
DigitalOut ledB(LED3);

//Defino como entradas los 3 pulsadores (para Red, Green y Blue) y el pulsador para el reseteo
DigitalIn E1r(D2);  //Pulsador para el color Rojo  (R)
DigitalIn E2r(D3);  //Pulsador para el color Verde (G)
DigitalIn E3r(D4);  //Pulsador para el color Azul  (B)
DigitalIn reseteo(D5);

//Variables donde guardo los valores de las entradas de los 3 colores
int E1; // <-- E1r
int E2; // <-- E2r
int E3; // <-- E3r

//Creo los tickers
Ticker pantalla;
Ticker mostrarLeds;
Ticker Interludio;

//Las funciones de cada ticker respectivamente
void visualizaTexto();      //Muestra en el Hercules los datos cada vez que se entra a la función
void visualizaSecuencia();  //Hace que, cada cierto tiempo, se prenda el led correspondiente a la parte de la secuencia en la que está  
void tiempoLedsOn();        //Define básicamente cuánto tiempo quedan prendidos los leds antes de apagarse otra vez para esperar el próx.color o botón presionado

//Función encargada del reseteo de todas las variables y volver al estado inicial de cada máquina de estados
void reset();

//Funciones que son las máquinas de estados
void detectorPulsado();     //Detecta qué botón de los 3 de colores tocaste quitando el rebote
void generadorSecuencia();  //Genera la secuencia
void confirmacion();        //Confirma si lo ingresado con los pulsadores corresponde con la secuencia

//Variables que indican los estados de las máquinas de estados
int estadosPulsadores;
int estadosSecuencia;
int estadosConfirm;


int vecR[MaxElem];
int vecG[MaxElem];
int vecB[MaxElem];
int vecE1[MaxElem];
int vecE2[MaxElem];
int vecE3[MaxElem];

//Variable que determina si se tiene que generar una nueva secuencia o no (Habilita Generación)
int HG;
//Variable que indica la Cantidad Total de posiciones de la secuencia
int CT=0;
//Variable que indica en cuál de las posiciones de la secuencia está en el momento (Estado Parcial)
int EP;
//Variable que guarda un número random del cuál depende cuál color se va a guardar en esa posición de la secuencia
int LED;

//Variables que cuentan diferentes cosas
int iSecuencia=0;   //Posición de la secuencia para generar la secuencia
int iIngresado=0;   //Cantidad de veces que algo fue ingresado mediante los pulsadores
int iCorrecto=0;    //Cantidad de veces que lo ingresado fue correcto / coincide con la secuencia
int iChequeo=0;     //Posición para chequear si lo ingresado fue correcto / coincide con la secuencia
int iMuestra=0;     //Posición para mostrar la secuencia en los leds 

//Variables que sirven para eliminar el rebote de los pulsadores y detectar solo el flanco ascendente
int mantieneRojo=0;
int mantieneVerde=0;
int mantieneAzul=0;

//Variable que indica si se tienen que mostrar los printf o no en el Hercules
int print=0;
//Variable que, según su valor, indica si los leds tienen que estar apagados o mantener su estado
int decideLedOff=0;

//Variables que se usan para pasar por las posiciones de los vectores cuando estos se tienen que reiniciar o se quiere mostrar la secuencia en el Hercules
int j;
int w;
int p;

//Variable que indica si se tienen que prender los leds con respecto a las posiciones de la secuencia
int doSec=0;

int main(void) {
    //Configuro en modo Pull-Up las 4 entradas con pulsadores 
    E1r.mode(PullUp);
    E2r.mode(PullUp);
    E3r.mode(PullUp);
    reseteo.mode(PullUp);
    //Apago los leds
    ledR=1;
    ledG=1;
    ledB=1;
    //Asigno las funciones a los tickers
    pantalla.attach(&visualizaTexto,1);             //Se ejecuta visualizaTexto cada 1 segundo
    mostrarLeds.attach(&visualizaSecuencia,0.6);    //Se ejecuta visualizaSecuencia cada 0,6 segundos 
    Interludio.attach(&tiempoLedsOn,0.2);           //Se ejecuta tiempoLedsOn cada 0,2 segundos
    while(true) {
        //Llamo a la función reset todo el tiempo
        reset();
        //Si la cantidad total de elementos de una secuencia todavía no pasó el máximo permitido, se ejecutan las funciones y muestran los printf
        //Sino, se para todo y se indica al jugador que debe apretar el botón reset para empezar de nuevo
        if(CT<=MaxElem)
        {
            detectorPulsado();
            confirmacion();
            generadorSecuencia();
            if(print==1)
            {
                printf("Cant. Total Secuencia:%d \n",CT);
                printf("Cant. Total de veces Ingresado:%d \n",iIngresado);
                printf("Cant. Total de veces que fue correcto lo ingresado:%d \n",iCorrecto);
                printf("Secuencia a lograr: \n");
                printf("R G B \n");
                for(p=0;p<=(CT-1);p++)
                {
                    if(CT==MaxElem+1)
                    {
                        break;   
                    }
                    printf("%d %d %d \n",vecR[p],vecG[p],vecB[p]);   
                }  
                printf("\n \n");
                print=0;   
            }
        }
        else
        {
            if(print==1)
            {
                printf("Por favor, empiece otra vez \n");
                print=0;  
            }
        }
    }
}

void reset()
{
    //Resetea todas las variables, los vectores y vuelve a los estados iniciales de las máquinas de estados
    if(reseteo==0)
    {
        for(j=0;j<MaxElem;j++)
        {
            vecR[j]=0;
            vecG[j]=0;
            vecB[j]=0;
            vecE1[j]=0;
            vecE2[j]=0;
            vecE3[j]=0;
        }
        CT=0;
        HG=0;
        EP=0;
        doSec=0;
        decideLedOff=0;
        print=0;
        LED=0;
        mantieneRojo=0;
        mantieneVerde=0;
        mantieneAzul=0;
        iSecuencia=0;
        iIngresado=0;
        iCorrecto=0;
        iChequeo=0;
        estadosSecuencia=NO_MUESTRA;
        estadosConfirm=NO_INGRESA;        
    }
}

void visualizaTexto()
{
    //Cada 1 segundo, esto se pone en 1 para mostrar los printf. Al instante se vuelve 0 y deja de mostrar los printf, esperando que se vuelva a llamar a la función
    print=1;   
}

void visualizaSecuencia()
{
    //Cada 0,6 segundos, la variable se hace 1. Cuando llegue la parte de mostrar la secuencia, la variable se va a hacer 0 y va a esperar a que se llame a la función otra vez
    doSec=1;     
}

void tiempoLedsOn()
{   
    //Cada 0,2 segundos, se le suma 1 a la variable y, cada vez que es par, apaga los leds sin importar sus estados anteriores
    if(decideLedOff%2==0)
    {
        ledR=1;
        ledG=1;
        ledB=1;
    }
    decideLedOff++;
}

void detectorPulsado()
{
    switch(estadosPulsadores)
    {
        default:
        case LEE:
        //Espera a que se toque el pulsador de rojo
        //Si es así guarda eso en los vectores, pone la variable E1 en 1, suma 1 a iIngresado y prende el led rojo, que va a ser apagado por la función tiempoLedsOn
        //También se pone en 1 la variable mantieneRojo que es un indicador del estado anterior
        //Cambia el estado a APAGA
        if(E1r==0 && mantieneRojo==0)
        {
            E1=1;
            mantieneRojo=1;
            vecE1[iIngresado]=1;
            vecE2[iIngresado]=0;
            vecE3[iIngresado]=0;
            ledR=0;
            iIngresado++;
            estadosPulsadores=APAGA;
        }
        //Espera a que se toque el pulsador de Verde
        //Si es así guarda eso en los vectores, pone la variable E2 en 1, suma 1 a iIngresado y prende el led verde, que va a ser apagado por la función tiempoLedsOn
        //También se pone en 1 la variable mantieneVerde que es un indicador del estado anterior
        //Cambia el estado a APAGA
        if(E2r==0 && mantieneVerde==0)
        {
            E2=1;
            mantieneVerde=1;
            vecE1[iIngresado]=0;
            vecE2[iIngresado]=1;
            vecE3[iIngresado]=0;
            ledG=0;
            iIngresado++;
            estadosPulsadores=APAGA;
        }
        //Espera a que se toque el pulsador de Azul
        //Si es así guarda eso en los vectores, pone la variable E3 en 1, suma 1 a iIngresado y prende el led verde, que va a ser apagado por la función tiempoLedsOn
        //También se pone en 1 la variable mantieneAzul que es un indicador del estado anterior
        //Cambia el estado a APAGA
        if(E3r==0 && mantieneAzul==0)
        {
            E3=1;
            mantieneAzul=1;
            vecE1[iIngresado]=0;
            vecE2[iIngresado]=0;
            vecE3[iIngresado]=1;
            ledB=0;
            iIngresado++;
            estadosPulsadores=APAGA;
        }
        break;
        
        case APAGA:
        //Si el pulsador de uno de los colores se mantiene pulsado y ya pasó por el estado anterior, E1 se vuelve 0 (E1 va a estar en 1 por muy poco tiempo)
        //Se pasa al estado AGUARDA
        if(E1r==0 && mantieneRojo==1)
        {
            E1=0;
            estadosPulsadores=AGUARDA;
        }
        //Si el pulsador de uno de los colores se mantiene pulsado y ya pasó por el estado anterior, E2 se vuelve 0 (E2 va a estar en 1 por muy poco tiempo)
        //Se pasa al estado AGUARDA
        if(E2r==0 && mantieneVerde==1)
        {
            E2=0;
            estadosPulsadores=AGUARDA;
        }
        //Si el pulsador de uno de los colores se mantiene pulsado y ya pasó por el estado anterior, E3 se vuelve 0 (E3 va a estar en 1 por muy poco tiempo)
        //Se pasa al estado AGUARDA
        if(E3r==0 && mantieneAzul==1)
        {
            E3=0;
            estadosPulsadores=AGUARDA;
        }
        break;
        
        case AGUARDA:
        //Si ya se tocó el pulsador una vez y ahora se suelta, el E se mantiene como estaba, se indica con la otra variable que terminó el proceso y vuelve al estado LEE
        if(E1r==1 && mantieneRojo==1)
        {
            E1=0;
            mantieneRojo=0;
            estadosPulsadores=LEE;
        }
        if(E2r==1 && mantieneVerde==1)
        {
            E2=0;
            mantieneVerde=0;
            estadosPulsadores=LEE;
        }
        if(E3r==1 && mantieneAzul==1)
        {
            E3=0;
            mantieneAzul=0;
            estadosPulsadores=LEE;
        }
        break;   
    }
}

void confirmacion(){
    switch(estadosConfirm)
    {
        default:
        case NO_INGRESA:
        //Se reinicia el contenido de los vectores de entrada, así cuando completás una secuencia tenés que escribir toda la que sigue desde cero
        //El contenido de los vectores de secuencia, que guardan los colores y su posición en la secuencia, no se reinicia porque es parte del juego que la secuencia
        //siguiente siempre es igual que la anterior solo que con un color random más agregado al final
        for(w=0;w<MaxElem;w++)
        {
            vecE1[w]=0;
            vecE2[w]=0;
            vecE3[w]=0;
        }
        //Se reinician los indicadores cuando completás una secuencia
        iIngresado=0;
        iChequeo=0;
        iCorrecto=0;
        //Se habilita la generación de una nueva secuencia
        HG=1;
        //Se pasa directamente al siguiente estado
        estadosConfirm=ESPERA;
        break;
        
        case INGRESA:
        //Se le suma 1 a iChequeo para que la proxima vez que se ingrese algo lo verifique con la siguiente posición de la secuencia
        iChequeo++;
        //Pasa directamente a ESPERA
        estadosConfirm=ESPERA;
        break;
        
        case ESPERA:
        //Automáticamente se deshabilita la generación
        HG=0;
        //Si no se ingresa nada mediante los pulsadores, queda en ESPERA
        if(E1==0 && E2==0 && E3==0)
        {
            estadosConfirm=ESPERA;
        }
        //Si se ingresa algo, se fija si esa posición concuerda con la misma posición de la secuencia
        //De ser correcto, va a INGRESA
        //De ser incorrecto, el jugador perdió cambia el estado a FIN
        else
        {
            if(iCorrecto!=CT)
            {
                if((vecR[iChequeo]==vecE1[iChequeo]) && (vecG[iChequeo]==vecE2[iChequeo]) && (vecB[iChequeo]==vecE3[iChequeo]))
                {
                    iCorrecto++; 
                    estadosConfirm=INGRESA;
                }
                else
                {
                    estadosConfirm=FIN;   
                }
            }
        }
        //Si se ingresó toda la secuencia correctamente, vuelve al estado inicial NO_INGRESA donde se va a habilitar una nueva generación y reiniciar variables
        if(iCorrecto==CT)
        {
            estadosConfirm=NO_INGRESA;
        }
        break;
        
        case FIN:
        //En caso de perder, se hace que CT sea mayor a la máxima cantidad de elementos posibles, condición en la que se termina el juego y espera el reseteo
        CT=MaxElem+1;
        break;
    }
}
void generadorSecuencia(){
    switch(estadosSecuencia)
    {
        default:
        case NO_MUESTRA:
        //La variable LED empieza en 0, que no hace nada
        LED=0;
        //Si se habilitó la generación de una secuencia, pasa al siguiente estado, NO_MUESTRA2
        //Sino, se queda en este estado
        if(HG==0)
        {
            estadosSecuencia=NO_MUESTRA;
        }
        else
        {
            estadosSecuencia=NO_MUESTRA2;
        }
        break;
        
        case NO_MUESTRA2:
        //De ser habilitada la generación de una nueva secuencia, se le suma 1 a la cantidad total de elementos/posiciones que va a tener la secuencia
        //CT empieza en 0, cuando se habilita la generación, CT pasa a ser 1, entonces dentro de la secuencia solo va a haber un color random
        //Cuando se toque bien ese color, vuelve a generar una secuencia, solo que ahora va a hacer CT++ otra vez y la secuencia va a constar de 2 colores random
        CT++;
        //Pasa a MUESTRA directamente
        estadosSecuencia=MUESTRA;
        break;
        
        case MUESTRA:
        //Si el estado parcial en que se encuentra no es último de la secuencia, hace que LED sea un número random entre 1 y 3
        //Basado en eso decide que color corresponde a ese estado parcial/posición de la secuencia
        //Eso lo guarda en los vectores de secuencia, que tienen qué color corresponde a qué posición
        //EP empieza en 0 y solo se reinicia en el reset, de manera que siempre se va a añadir un color random al final de la secuencia anterior para hacer la nueva
        if(EP!=CT)
        {
            LED=rand()%3+1;
            if(LED==1)
            {
                vecR[iSecuencia]=1;
                vecG[iSecuencia]=0;
                vecB[iSecuencia]=0;
            }
            else if(LED==2)
            {
                vecR[iSecuencia]=0;
                vecG[iSecuencia]=1;
                vecB[iSecuencia]=0;
            }
            else if(LED==3)
            {
                vecR[iSecuencia]=0;
                vecG[iSecuencia]=0;
                vecB[iSecuencia]=1;
            }
            if(iSecuencia<CT)
            {
                iSecuencia++;
            }
            EP++;
        }
        //Al hacerlo una vez, EP pasa a ser igual que CT, por lo que cambia al estado MUESTRA2 y espera a que el proceso se vuelva a hacer para que CT valga más que EP
        //(En el estado anterior con CT++)
        else
        {
            estadosSecuencia=MUESTRA2;
        }
        break;
            
        case MUESTRA2:
        //Cada 1 segundo que doSec se hace 1 y pasa a ser 0 instantáneamente, los leds se prenden con respecto a la secuencia generada (guardada en los vectores)
        //Se apagan con la funcion tiempoLedsOn
        //El estado de los leds es igual a lo que contiene la posición del vector -negado- porque los leds se prenden con 0, no con 1
        //Los vectores guardan con 1 los leds que se tienen que prender
        //Cuando se muestra toda la secuencia en los leds, se reinicia iMuestra y vuelve al estado inicial NO_MUESTRA
        if(doSec==1)
        {
            //La secuencia se guarda desde la posición 0 de los vectores. La primera secuencia se hace con CT=1. Por eso el CT-1
            if(iMuestra<=CT-1)
            {
                ledR=!vecR[iMuestra];
                ledG=!vecG[iMuestra];
                ledB=!vecB[iMuestra];
                iMuestra++;
            }
            else
            {
                iMuestra=0;
                estadosSecuencia=NO_MUESTRA;
            }
            doSec=0;
        }
        break;
    }
}