/********
 Bases simples para recrear el juego TETRIS en modo texto y monoProceso
********/

#include <conio.h>
#include <stdlib.h>
#include <dos.h>
#include <time.h>

// Ya que el lenguaje carece de BOOLEANOS definimos unas macros
#define bool  int
#define true    1
#define false   0

// N£mero de piezas con las que jugamos
#define NUMERO_DE_PIEZAS 7
#define ANCHO_TABLERO 15
#define ALTO_TABLERO  23

typedef enum tipoPieza { PIEZA_CUADRADA=1, PIEZA_LINEA, PIEZA_Rizq, PIEZA_Rder, PIEZA_Lder, PIEZA_Lizq,PIEZA_T };


// Definimos que es para nosotros una pieza
typedef struct {
 tipoPieza tipo;                // Tipo de pieza que estamos definiendo
 int rotacion, proxRot;         // Estado ¢ rotaci¢n actual de la pieza
 int posX, posY, proxX;         // Coordenadas de la pieza
} pieza;

// Definimos una partida
typedef struct {
                                // Necesitamos un tablero para jugar
 char tablero[ALTO_TABLERO][ANCHO_TABLERO];

 pieza piezaActual;             // e informaci¢n de la pieza en juego

 int lineas;                    // Estad¡sticas del n£mero de lineas conseguidas
 int piezas;                    // Estad¡sticas del n£mero de piezas jugadas
 int puntuacion;                // Puntuaci¢n actual para esta partida
} partida;

pieza obtenerPieza(void);
void  AnimaticaTimeSlice(void);
void dibujaPieza( pieza P, int color );
pieza obtenerPieza(void);
void procesaTecla( bool *salir, bool *pausa, bool *tocaMover );
void dibujaPieza( pieza P, int color );
 void dibujaPiezaSOLIDA( pieza P, int color );
 void dibujaPiezaHUECA( pieza P, int color );
int anchoPieza( pieza P );
int altoPieza( pieza P );
void muestraTablero(void);
bool piezaColisiona( char tablero[ALTO_TABLERO][ANCHO_TABLERO], pieza P );
bool actualizaFicha(bool bajarFicha);
int colorPieza(pieza P);
void procesaColision();
void fijaPieza();
/*******************************************************************/

partida partidaActual;
bool pSolida=true;

void eliminaLineaTablero( int Y )
{
 int i,j;
       for (i=0;i<ANCHO_TABLERO;i++)
        for (j=Y;j>0;j--)
          partidaActual.tablero[j][i] = partidaActual.tablero[j-1][i];

       for (i=0;i<ANCHO_TABLERO;i++)
          partidaActual.tablero[0][i] = 0;
};

void RedibujaTablero(void)
{
 for (int i=0; i<ANCHO_TABLERO; i++)
  for (int j=0; j<ALTO_TABLERO; j++)
  {
   gotoxy(i*2+2,j+1); textcolor( partidaActual.tablero[j][i] );
   cprintf("ÛÛ");
  }
};

void inicializaJuego(void)
{
 randomize();                   // Inicializamos el generador de numeros

 partidaActual.lineas = 0;      // Inicializamos las estadisticas
 partidaActual.piezas = 0;
 partidaActual.puntuacion = 0;

 for(int i=0;i<ANCHO_TABLERO;i++)          // Vaciamos el tablero
  for(int j=0;j<ALTO_TABLERO;j++)
   partidaActual.tablero[j][i] = 0;

 partidaActual.piezaActual = obtenerPieza();
}

// Genera de forma aleatoria una pieza y un estado (rotacion)
pieza obtenerPieza(void)
{
  pieza p;

  p.tipo     = random(NUMERO_DE_PIEZAS)+1;
  p.rotacion = random(4);
  p.proxRot  = p.rotacion;

  p.posX  = 3;
  p.proxX = 3;
  p.posY  = 0;//altoPieza(p)-1;
  return p;
}

// Procesamos las posible teclas
void procesaTecla( bool *salir, bool *pausa, bool *tocaMover )
{
 switch( getch() )
 {
  case 'B':
  case 'b':
       pSolida = true;
       break;
  case 'h':
  case 'H':
       pSolida = false;
       break;
  case 't':
           partidaActual.piezaActual.tipo = (partidaActual.piezaActual.tipo+1)%7;
           break;
  case 's':
  case 'S':
           *salir = true;
           break;
  case 'p':
  case 'P':
           *pausa = (*pausa==false) ? true : false;
           break;
  case 'N':
  case 'n':
           muestraTablero();
           inicializaJuego();
           break;
  // Teclas especiales
  case 0:
       switch( getch() )
       {
        // Flecha izquierda
        case 75:
                 // Solo si no estamos en el borde del tablero
                 if ( partidaActual.piezaActual.posX > 0 )
                                partidaActual.piezaActual.proxX = partidaActual.piezaActual.posX-1;
             break;
        // Flecha derecha
        case 77:
                if ((partidaActual.piezaActual.posX+anchoPieza(partidaActual.piezaActual)) < ANCHO_TABLERO)
                   partidaActual.piezaActual.proxX = partidaActual.piezaActual.posX+1;
             break;
        // Flecha arriba
        case 72:
               partidaActual.piezaActual.proxRot = (partidaActual.piezaActual.rotacion+1)%4;
             break;
        // Flecha Abajo
        case 80:
               *tocaMover = true;
               break;
       }
 }
}

// Nuestras posibles piezas
void dibujaPieza( pieza P, int color )
{
 if ( pSolida ) dibujaPiezaSOLIDA(P,color);
 else dibujaPiezaHUECA(P,color);
}

void dibujaPiezaSOLIDA( pieza P, int color )
{
 int X, Y;
 X = P.posX*2+2;          // Coordenas iniciales para dibujar
 Y = P.posY+1;          // mas una correcci¢n visual (hay que encajar
                        // el tablero en la pantalla)

 textcolor(color);      // Establecemos el color de la pieza

 switch( P.tipo )
 {
  /*******************
     ROTACION 0    ROTACION 1    ROTACION 2    ROTACION 3
  *********************/

  //  ÛÛÛÛ           ÛÛÛÛ          ÛÛÛÛ          ÛÛÛÛ
  //  ÛÛÛÛ           ÛÛÛÛ          ÛÛÛÛ          ÛÛÛÛ
  case PIEZA_CUADRADA:
   switch( P.rotacion )
   {
    case 0:
         gotoxy(X,Y);   cprintf("ÛÛÛÛ");
         gotoxy(X,Y+1); cprintf("ÛÛÛÛ");
         break;
    case 1:
         gotoxy(X,Y);   cprintf("ÛÛÛÛ");
         gotoxy(X,Y+1); cprintf("ÛÛÛÛ");
         break;
    case 2:
         gotoxy(X,Y);   cprintf("ÛÛÛÛ");
         gotoxy(X,Y+1); cprintf("ÛÛÛÛ");
         break;
    case 3:
         gotoxy(X,Y);   cprintf("ÛÛÛÛ");
         gotoxy(X,Y+1); cprintf("ÛÛÛÛ");
         break;
   }
   break;
  //  ÛÛ
  //  ÛÛ            ÛÛÛÛÛÛ        ÛÛÛÛÛÛ        ÛÛÛÛÛÛ
  //  ÛÛ
  case PIEZA_LINEA:
   switch( P.rotacion )
   {
    case 0:
         gotoxy(X,Y);   cprintf("ÛÛ");
         gotoxy(X,Y+1); cprintf("ÛÛ");
         gotoxy(X,Y+2); cprintf("ÛÛ");
         break;
    case 1:
         gotoxy(X,Y);   cprintf("ÛÛÛÛÛÛ");
         break;
    case 2:
         gotoxy(X,Y);   cprintf("ÛÛ");
         gotoxy(X,Y+1); cprintf("ÛÛ");
         gotoxy(X,Y+2); cprintf("ÛÛ");
         break;
    case 3:
         gotoxy(X,Y);   cprintf("ÛÛÛÛÛÛ");
         break;
   }
   break;
  //                  ÛÛ                           ÛÛ
  //  ÛÛÛÛ          ÛÛÛÛ          ÛÛÛÛ           ÛÛÛÛ
  //    ÛÛÛÛ        ÛÛ              ÛÛÛÛ         ÛÛ
  case PIEZA_Rizq:
   switch( P.rotacion )
   {
    case 0:
         gotoxy(X,Y);         cprintf("ÛÛÛÛ");
         gotoxy(X+2,Y+1);       cprintf("ÛÛÛÛ");
         break;
    case 1:
         gotoxy(X+2,Y);         cprintf("ÛÛ");
         gotoxy(X,Y+1);       cprintf("ÛÛÛÛ");
         gotoxy(X,Y+2);       cprintf("ÛÛ");
         break;
    case 2:
         gotoxy(X,Y);         cprintf("ÛÛÛÛ");
         gotoxy(X+2,Y+1);       cprintf("ÛÛÛÛ");
         break;
    case 3:
         gotoxy(X+2,Y);         cprintf("ÛÛ");
         gotoxy(X,Y+1);       cprintf("ÛÛÛÛ");
         gotoxy(X,Y+2);       cprintf("ÛÛ");
         break;
   }
   break;
  //                ÛÛ                           ÛÛ
  //   ÛÛÛÛ         ÛÛÛÛ            ÛÛÛÛ         ÛÛÛÛ
  // ÛÛÛÛ             ÛÛ          ÛÛÛÛ             ÛÛ
  case PIEZA_Rder:
   switch( P.rotacion )
   {
    case 0:
         gotoxy(X+2,Y)  ;       cprintf("ÛÛÛÛ");
         gotoxy(X,Y+1);       cprintf("ÛÛÛÛ");
         break;
    case 1:
         gotoxy(X,Y);         cprintf("ÛÛ");
         gotoxy(X,Y+1);       cprintf("ÛÛÛÛ");
         gotoxy(X+2,Y+2);       cprintf("ÛÛ");
         break;
    case 2:
         gotoxy(X+2,Y);           cprintf("ÛÛÛÛ");
         gotoxy(X,Y+1);         cprintf("ÛÛÛÛ");
         break;
    case 3:
         gotoxy(X,Y);         cprintf("ÛÛ");
         gotoxy(X,Y+1);       cprintf("ÛÛÛÛ");
         gotoxy(X+2,Y+2);       cprintf("ÛÛ");
         break;
   }
   break;
  // ÛÛ                           ÛÛÛÛ
  // ÛÛ            ÛÛÛÛÛÛ           ÛÛ             ÛÛ
  // ÛÛÛÛ          ÛÛ               ÛÛ         ÛÛÛÛÛÛ
  case PIEZA_Lizq:
   switch( P.rotacion )
   {
    case 0:
         gotoxy(X,Y);       cprintf("ÛÛ");
         gotoxy(X,Y+1);     cprintf("ÛÛ");
         gotoxy(X,Y+2);     cprintf("ÛÛÛÛ");
         break;
    case 1:
         gotoxy(X,Y);       cprintf("ÛÛÛÛÛÛ");
         gotoxy(X,Y+1);     cprintf("ÛÛ");
         break;
    case 2:
         gotoxy(X,Y);       cprintf("ÛÛÛÛ");
         gotoxy(X+2,Y+1);     cprintf("ÛÛ");
         gotoxy(X+2,Y+2);     cprintf("ÛÛ");
         break;
    case 3:
         gotoxy(X+4,Y);         cprintf("ÛÛ");
         gotoxy(X,Y+1);     cprintf("ÛÛÛÛÛÛ");
         break;
   }
   break;
  //   ÛÛ                         ÛÛÛÛ
  //   ÛÛ          ÛÛ             ÛÛ           ÛÛÛÛÛÛ
  // ÛÛÛÛ          ÛÛÛÛÛÛ         ÛÛ               ÛÛ
  case PIEZA_Lder:
   switch( P.rotacion )
   {
    case 0:
         gotoxy(X+2,Y);       cprintf("ÛÛ");
         gotoxy(X+2,Y+1);     cprintf("ÛÛ");
         gotoxy(X,Y+2);     cprintf("ÛÛÛÛ");
         break;
    case 1:
         gotoxy(X,Y);     cprintf("ÛÛ");
         gotoxy(X,Y+1);   cprintf("ÛÛÛÛÛÛ");
         break;
    case 2:
         gotoxy(X,Y);     cprintf("ÛÛÛÛ");
         gotoxy(X,Y+1);   cprintf("ÛÛ");
         gotoxy(X,Y+2);   cprintf("ÛÛ");
         break;
    case 3:
         gotoxy(X,Y);       cprintf("ÛÛÛÛÛÛ");
         gotoxy(X+4,Y+1);       cprintf("ÛÛ");
         break;
   }
   break;
  //               ÛÛ                            ÛÛ
  //   ÛÛ          ÛÛÛÛ         ÛÛÛÛÛÛ         ÛÛÛÛ
  // ÛÛÛÛÛÛ        ÛÛ             ÛÛ             ÛÛ
  case PIEZA_T:
   switch( P.rotacion )
   {
    case 0:
         gotoxy(X+2,Y);     cprintf("ÛÛ");
         gotoxy(X,Y+1);    cprintf("ÛÛÛÛÛÛ");
         break;
    case 1:
         gotoxy(X,Y);       cprintf("ÛÛ");
         gotoxy(X,Y+1);     cprintf("ÛÛÛÛ");
         gotoxy(X,Y+2);     cprintf("ÛÛ");
         break;
    case 2:
         gotoxy(X,Y);       cprintf("ÛÛÛÛÛÛ");
         gotoxy(X+2,Y+1);     cprintf("ÛÛ");
         break;
    case 3:
         gotoxy(X+2,Y);       cprintf("ÛÛ");
         gotoxy(X,Y+1);     cprintf("ÛÛÛÛ");
         gotoxy(X+2,Y+2);     cprintf("ÛÛ");
         break;
   }
   break;
 }

}
/* Devuelve la anchura de una pieza segun su tipo y rotacion actual
*/

int anchoPieza( pieza P )
{
 int anchuraPiezas[8][4]={ {0,0,0,0},{2,2,2,2}, {1,3,1,3}, {3,2,3,2},
                        {3,2,3,2}, {2,3,2,3}, {2,3,2,3},
                        {3,2,3,2} };

 return anchuraPiezas[P.tipo][P.rotacion];
}

/* Devuelve la altura de una pieza segun su tipo y rotacion actual
*/
int altoPieza( pieza P )
{
 int alturaPiezas[8][4]={ {0,0,0,0}, {2,2,2,2}, {3,1,3,1}, {2,3,2,3},
                        {2,3,2,3}, {3,2,3,2}, {3,2,3,2},
                        {2,3,2,3} };

 return alturaPiezas[P.tipo][P.rotacion];
}

void muestraTablero(void)
{
 int i;

 clrscr();

 /* MARCO DEL TABLERO */
 textcolor( LIGHTGREEN );
                       //123456789-123456789-123456789-
 gotoxy(1,1); cprintf( "¿                              ÃÄÄÄÄÄ>");
 textcolor( GREEN );
                                                   cprintf(" T E T R I S ");
 textcolor( LIGHTGREEN );
                                                                 cprintf("<ÄÄÄ--- - ú");
 for(i=0;i<ALTO_TABLERO; i++)
 {
  gotoxy(1,i+2); cprintf("³                              ³");
 }
 gotoxy(1,24);   cprintf("ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ");

 /// Informacion de las teclas
 gotoxy(35,18); textcolor(RED); cprintf("N"); textcolor(BLUE); cprintf("ueva Partida");
 gotoxy(35,19); textcolor(RED); cprintf("P"); textcolor(BLUE); cprintf("ausa");

 gotoxy(35,23); textcolor(RED); cprintf("B"); textcolor(BLUE); cprintf("loques Solidos");
 gotoxy(35,24); textcolor(RED); cprintf("H"); textcolor(BLUE); cprintf("uecos");
}


// Punto de entrada a la aplicacion
void main(void)
{
 clock_t start;
 bool salir, pausa, colision;   // L¢gicos de control
 bool tocaMover = true;

 inicializaJuego();             // Inicializamos el juego Actual
 muestraTablero();              // Mostramos el Tablero

 salir = false;
 pausa = false;
                                // Entramos en un bucle cuyo £nico fin
                                // ser  para acabar el programa
 while( !salir )
 {
  /****** BLOQUE DE CONTROL DE COMANDOS
          Se encarga (sin detener la ejecuci¢n del programa de procesar
          las teclas pulsadas por el usuario).
  *******/
  if ( kbhit() )                // Solo si hay alguna tecla en el buffer
    procesaTecla(&salir,&pausa,&tocaMover);// procesamos dicha tecla
  // vaciar buffer
  while( kbhit() ) getch();
  /****** BLOQUE DE RETARDO
          Se encarga de indicar si ha de actualizarse los movimientos de
          las fichas o no (sin detener la ejecuci¢n del programa).
          NOTA: temporalmente se ha colocado un "delay" hasta terminar el
                bloque.
  *******/
  if ( tocaMover == false )
    tocaMover = ( ( clock() - start ) / CLK_TCK > 0.5 ) ? true : false ;

  /****** BLOQUE DE ACTUALIZACION DE FICHA
          Actualiza la posici¢n actual de la FICHA en el tablero e informa
          de posibles colisiones (choque con otras piezas).
  *******/
  if ( !pausa )
  {
    // Si no estamos en pausa y la pieza ha cambiado
    if ( tocaMover==true || (partidaActual.piezaActual.proxX!=partidaActual.piezaActual.posX || partidaActual.piezaActual.rotacion != partidaActual.piezaActual.proxRot ) )
      colision = actualizaFicha(tocaMover);
    /**** SEGUNDA MITAD DEL CONTROL DE TIEMPO */
    if ( tocaMover == true )
    {
     start = clock();
     tocaMover = false;
    }

  /****** CONTROL DE COLISIONES
          Fija la ficha en el tablero en caso de colision y procesa
          posibles eliminaciones de linea/piezas.
  *******/
  if ( colision )
  {
     fijaPieza();                       // Fijamos la pieza en el tablero
     procesaColision();                 // Procesamos la colision
     partidaActual.piezaActual = obtenerPieza();
     colision = false;
     tocaMover = true;
  }

  // Demostracion de que nada se detiene
  AnimaticaTimeSlice();
 }
 }
}

// Hacemos la ficha permanente en el tablero
void fijaPieza()
{
 int X,Y, rotacion;       // posicion base
 X = partidaActual.piezaActual.posX;
 Y = partidaActual.piezaActual.posY;
 rotacion = partidaActual.piezaActual.rotacion;

 switch ( partidaActual.piezaActual.tipo )
 {
  case PIEZA_CUADRADA:
       partidaActual.tablero[Y][X]      =PIEZA_CUADRADA;
       partidaActual.tablero[Y+1][X]    =PIEZA_CUADRADA;
       partidaActual.tablero[Y][X+1]    =PIEZA_CUADRADA;
       partidaActual.tablero[Y+1][X+1]  =PIEZA_CUADRADA;
     break;
  case PIEZA_LINEA:
     if ( rotacion == 0 || rotacion == 2 )
     {
       partidaActual.tablero[Y][X]  =PIEZA_LINEA;
       partidaActual.tablero[Y+1][X]=PIEZA_LINEA;
       partidaActual.tablero[Y+2][X]=PIEZA_LINEA;
     } else {
       partidaActual.tablero[Y][X]  =PIEZA_LINEA;
       partidaActual.tablero[Y][X+1]=PIEZA_LINEA;
       partidaActual.tablero[Y][X+2]=PIEZA_LINEA;
     }
    break;
  case PIEZA_Lizq:
     switch( rotacion )
     {
      case 0:                        // |_
           partidaActual.tablero[Y][X]     = PIEZA_Lizq;
           partidaActual.tablero[Y+1][X]   = PIEZA_Lizq;
           partidaActual.tablero[Y+2][X] = PIEZA_Lizq;
           partidaActual.tablero[Y+2][X+1] = PIEZA_Lizq;
           break;
      case 1:                        // |ùùù
           partidaActual.tablero[Y][X]     = PIEZA_Lizq;
           partidaActual.tablero[Y+1][X]   = PIEZA_Lizq;
           partidaActual.tablero[Y][X+1] = PIEZA_Lizq;
           partidaActual.tablero[Y][X+2] = PIEZA_Lizq;
           break;
      case 2:                        // ù|
           partidaActual.tablero[Y][X]     = PIEZA_Lizq;
           partidaActual.tablero[Y][X+1]   = PIEZA_Lizq;
           partidaActual.tablero[Y+1][X+1] = PIEZA_Lizq;
           partidaActual.tablero[Y+2][X+1] = PIEZA_Lizq;
           break;
      case 3:                        // ___|
           partidaActual.tablero[Y][X+2]     = PIEZA_Lizq;
           partidaActual.tablero[Y+1][X]   = PIEZA_Lizq;
           partidaActual.tablero[Y+1][X+1] = PIEZA_Lizq;
           partidaActual.tablero[Y+1][X+2] = PIEZA_Lizq;
           break;
     }
     break;
  case PIEZA_Lder:
     switch( rotacion )
     {
      case 0:                        //  Ü
                                     // ÜÛ
           partidaActual.tablero[Y][X+1]     = PIEZA_Lder;
           partidaActual.tablero[Y+1][X+1]   = PIEZA_Lder;
           partidaActual.tablero[Y+2][X]     = PIEZA_Lder;
           partidaActual.tablero[Y+2][X+1]   = PIEZA_Lder;
          break;
      case 1:                        // ÛÜÜÜ
           partidaActual.tablero[Y][X]       = PIEZA_Lder;
           partidaActual.tablero[Y+1][X]     = PIEZA_Lder;
           partidaActual.tablero[Y+1][X+1]   = PIEZA_Lder;
           partidaActual.tablero[Y+1][X+2]   = PIEZA_Lder;
           break;
      case 2:                        // Ûß
                                     // Û
           partidaActual.tablero[Y][X]       = PIEZA_Lder;
           partidaActual.tablero[Y][X+1]     = PIEZA_Lder;
           partidaActual.tablero[Y+1][X]     = PIEZA_Lder;
           partidaActual.tablero[Y+2][X]   = PIEZA_Lder;
           break;
      case 3:                        // ßßßÛ
           partidaActual.tablero[Y][X]       = PIEZA_Lder;
           partidaActual.tablero[Y][X+1]     = PIEZA_Lder;
           partidaActual.tablero[Y][X+2]     = PIEZA_Lder;
           partidaActual.tablero[Y+1][X+2]   = PIEZA_Lder;
           break;
     }
     break;
  case PIEZA_Rizq:
     switch( rotacion )
     {
      case 0:                        // ßÛÜ
      case 2:
           partidaActual.tablero[Y][X]       = PIEZA_Rizq;
           partidaActual.tablero[Y][X+1]     = PIEZA_Rizq;
           partidaActual.tablero[Y+1][X+1]   = PIEZA_Rizq;
           partidaActual.tablero[Y+1][X+2]   = PIEZA_Rizq;
           break;
      case 1:                        // ÜÛ
      case 3:                        // ß
           partidaActual.tablero[Y][X+1]       = PIEZA_Rizq;
           partidaActual.tablero[Y+1][X+1]     = PIEZA_Rizq;
           partidaActual.tablero[Y+1][X]   = PIEZA_Rizq;
           partidaActual.tablero[Y+2][X]   = PIEZA_Rizq;
           break;
     }
     break;
  case PIEZA_Rder:
     switch( rotacion )
     {
      case 0:                        // ÜÛß
      case 2:
           partidaActual.tablero[Y][X+1]     = PIEZA_Rder;
           partidaActual.tablero[Y][X+2]     = PIEZA_Rder;
           partidaActual.tablero[Y+1][X]     = PIEZA_Rder;
           partidaActual.tablero[Y+1][X+1]   = PIEZA_Rder;
           break;
      case 1:                        // ÛÜ
      case 3:                        //  ß
           partidaActual.tablero[Y][X]       = PIEZA_Rder;
           partidaActual.tablero[Y+1][X]     = PIEZA_Rder;
           partidaActual.tablero[Y+1][X+1]   = PIEZA_Rder;
           partidaActual.tablero[Y+2][X+1]   = PIEZA_Rder;
           break;
     }
     break;
  case PIEZA_T:
     switch( rotacion )
     {
      case 0:                        // ÜÛÜ
           partidaActual.tablero[Y][X+1]       = PIEZA_T;
           partidaActual.tablero[Y+1][X]     = PIEZA_T;
           partidaActual.tablero[Y+1][X+1]   = PIEZA_T;
           partidaActual.tablero[Y+1][X+2]   = PIEZA_T;
           break;

      case 1:                        // ÛÜ
                                     // ß
           partidaActual.tablero[Y][X]       = PIEZA_T;
           partidaActual.tablero[Y+1][X]     = PIEZA_T;
           partidaActual.tablero[Y+1][X+1]   = PIEZA_T;
           partidaActual.tablero[Y+2][X]   = PIEZA_T;
           break;
      case 2:                        //ÜÜÜ
                                     // ß
           partidaActual.tablero[Y][X]       = PIEZA_T;
           partidaActual.tablero[Y][X+1]     = PIEZA_T;
           partidaActual.tablero[Y][X+2]   = PIEZA_T;
           partidaActual.tablero[Y+1][X+1]   = PIEZA_T;
           break;
      case 3:                        // ÜÛ
                                     //  ß
           partidaActual.tablero[Y][X+1]       = PIEZA_T;
           partidaActual.tablero[Y+1][X]     = PIEZA_T;
           partidaActual.tablero[Y+1][X+1]   = PIEZA_T;
           partidaActual.tablero[Y+2][X+1]   = PIEZA_T;
           break;
     }
     break;
 }
}

void procesaColision()
{
 int X,Y,A, i,j;
 bool noHayLINEA[3]={true,true,true}; // 3 es el alto MAXIMO de una PIEZA

 // Miramos la pieza actual y vemos si consiguio una linea...
 A = altoPieza( partidaActual.piezaActual );
 X = partidaActual.piezaActual.posX;
 Y = partidaActual.piezaActual.posY;

 // Vemos si DE LAS POSIBLES LINEAS (alto de la ficha) DONDE ENCAJO
 // alguna ha podido hacer linea.
 for( i=0; i<A && i<3; i++ )
 {
  noHayLINEA[i] = false;                 // Inicialmente HAY linea
  // En el momento que exista un HUECO en la HORIZONTAL, la cagaste
  for ( j=0; j<ANCHO_TABLERO && noHayLINEA[i]==false; j++ )
   noHayLINEA[i] = (partidaActual.tablero[Y+i][j] == 0) ? true : false;
 }

 // Ademas hace rato que me canse de "describir" y "comentar" el programa
 if ( noHayLINEA[0]==false || noHayLINEA[1]==false || noHayLINEA[2]==false )
 {
      // Actualizamos el tablero
      if ( noHayLINEA[0]==false )
        eliminaLineaTablero( Y );
      if ( noHayLINEA[1]==false )
        eliminaLineaTablero( Y+1 );
      if ( noHayLINEA[2]==false )
        eliminaLineaTablero( Y+2 );

    // ESTO DETENDRA LA EJECUCION DEL PROGRAMA
    // PERO WUUUEEENO, ESTO SOLO ES UN EJEMPLO QUE MAS QUEREIS
    for(i=0;i<10;i++)
     if ( noHayLINEA[j]==false )
     {
       for( j=0;j<A;j++) {
       gotoxy( 2,Y+1+j ); textcolor(GREEN);      cprintf("±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±");
       }
       delay(50);
       for( j=0;j<A;j++) {
       gotoxy( 2,Y+1+j ); textcolor(LIGHTGREEN); cprintf("²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²");
       }
       delay(100);
       for( j=0;j<A;j++) {
       gotoxy( 2,Y+1+j ); textcolor(WHITE);      cprintf("ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ");
       }
       delay(50);
     }

    RedibujaTablero();
 }
}

/*
 La colision de una pieza en el tablero, depende del tipo, rotacion
 y posiciones dentro de este.
*/
bool piezaColisiona( char tablero[ALTO_TABLERO][ANCHO_TABLERO], pieza P )
{
 bool colision;
 colision = false;

/*
    // Solo si no estamos en el borde del tablero
       colision =  ( P.posX < 0 );
*/
/*
    // COLISION por la derecha FRUTO DE UNA ROTACION
    colision = ( ((P.posX+anchoPieza(P)) > ANCHO_TABLERO) );
*/
    // Comprobamos una posible colision con la base del tablero
    if ( colision == false )
       colision = ((P.posY+altoPieza(P)) > ALTO_TABLERO );

    // Comprobamos colisiones DENTRO DEL TABLERO
    /***********/
    if ( colision == false && P.tipo==PIEZA_CUADRADA)
       colision = tablero[P.posY+1][P.posX]!=0 || tablero[P.posY+1][P.posX+1]!=0 ||
                  tablero[P.posY][P.posX]!=0 || tablero[P.posY][P.posX+1]!=0;

    if ( colision == false && P.tipo==PIEZA_LINEA )
    {
     if ( P.rotacion == 0 || P.rotacion == 2 )
       colision = tablero[P.posY+0][P.posX]!=0 ||
                  tablero[P.posY+1][P.posX]!=0 ||
                  tablero[P.posY+2][P.posX]!=0
                 ;
     else
       colision = (tablero[P.posY][P.posX]!=0 ||
                   tablero[P.posY][P.posX+1]!=0 ||
                   tablero[P.posY][P.posX+2]!=0 );
    }

    if ( colision == false && P.tipo==PIEZA_Lizq )
    {
     switch( P.rotacion )
     {
      case 0:                        // |_
           colision = tablero[P.posY+2][P.posX] != 0 ||
                      tablero[P.posY+2][P.posX+1] != 0 ||
                      tablero[P.posY+0][P.posX]!=0 ||
                      tablero[P.posY+1][P.posX]!=0;
           break;
      case 1:                        // |ùùù
           colision = tablero[P.posY+1][P.posX] != 0 ||
                      tablero[P.posY][P.posX+1] != 0 ||
                      tablero[P.posY][P.posX+2] != 0 ||
                      tablero[P.posY][P.posX]!=0;
           break;
      case 2:                        // ù|
           colision = tablero[P.posY][P.posX] != 0 ||
                      tablero[P.posY+2][P.posX+1] != 0||
                      tablero[P.posY+0][P.posX+1]!=0 ||
                      tablero[P.posY+1][P.posX+1]!=0;
           break;
      case 3:                        // |___
           colision = tablero[P.posY+1][P.posX] != 0 ||
                      tablero[P.posY+1][P.posX+1] != 0 ||
                      tablero[P.posY+1][P.posX+2] != 0 ||
                      tablero[P.posY][P.posX]!=0;
           break;
     }
    }

    if ( colision == false && P.tipo==PIEZA_Lder )
    {
     switch( P.rotacion )
     {
      case 0:                        //  Ü
                                     // ÜÛ
           colision = tablero[P.posY+2][P.posX] != 0 ||
                      tablero[P.posY+2][P.posX+1] != 0 ||
                      tablero[P.posY+0][P.posX+1]!=0 ||
                      tablero[P.posY+1][P.posX+1]!=0;
           break;
      case 1:                        // ÛÜÜÜ
           colision = tablero[P.posY+1][P.posX] != 0 ||
                      tablero[P.posY+1][P.posX+1] != 0 ||
                      tablero[P.posY+1][P.posX+2] != 0 ||
                      tablero[P.posY][P.posX]!=0;
           break;
      case 2:                        // Ûß
                                     // Û
           colision = tablero[P.posY][P.posX+1] != 0 ||
                      tablero[P.posY+2][P.posX] != 0 ||
                      tablero[P.posY][P.posX]!=0 ||
                      tablero[P.posY+1][P.posX]!=0;
           break;
      case 3:                        // ßßßÛ
           colision = tablero[P.posY][P.posX] != 0 ||
                      tablero[P.posY][P.posX+1] != 0 ||
                      tablero[P.posY+1][P.posX+2] != 0 ||
                      tablero[P.posY][P.posX+2]!=0;
           break;
     }
    }

    if ( colision == false && P.tipo==PIEZA_Rizq )
    {
     switch( P.rotacion )
     {
      case 0:                        // ßÛÜ
      case 2:
           colision = tablero[P.posY][P.posX] != 0 ||
                      tablero[P.posY+1][P.posX+1] != 0 ||
                      tablero[P.posY+1][P.posX+2] != 0 ||
                      tablero[P.posY][P.posX+1]!=0;
           break;
      case 1:                        // ÜÛ
      case 3:                        // ß
           colision = tablero[P.posY+2][P.posX] != 0 ||
                      tablero[P.posY+1][P.posX+1] != 0 ||
                      tablero[P.posY+1][P.posX]!=0 ||
                      tablero[P.posY+1][P.posX+1]!=0;
           break;
     }
    }

    if ( colision == false && P.tipo==PIEZA_Rder )
    {
     switch( P.rotacion )
     {
      case 0:                        // ÜÛß
      case 2:
           colision = tablero[P.posY+1][P.posX] != 0 ||
                      tablero[P.posY+1][P.posX+1] != 0 ||
                      tablero[P.posY][P.posX+2] != 0 ||
                      tablero[P.posY+0][P.posX+1]!=0;
           break;
      case 1:                        // ÛÜ
      case 3:                        //  ß
            colision = tablero[P.posY+1][P.posX] != 0 ||
                      tablero[P.posY+2][P.posX+1] != 0 ||
                      tablero[P.posY+1][P.posX]!=0 ||
                      tablero[P.posY+1][P.posX+1]!=0;
           break;
     }
    }

    if ( colision == false && P.tipo==PIEZA_T )
    {
     switch( P.rotacion )
     {
      case 0:                        // ÜÛÜ
           colision = tablero[P.posY+1][P.posX] != 0 ||
                      tablero[P.posY+1][P.posX+1] != 0 ||
                      tablero[P.posY+1][P.posX+2] != 0 ||
                      tablero[P.posY+0][P.posX+1]!=0;
           break;

      case 1:                        // ÛÜ
                                     // ß
           colision = tablero[P.posY+2][P.posX] != 0 ||
                      tablero[P.posY+1][P.posX+1] != 0 ||
                      tablero[P.posY+0][P.posX]!=0 ||
                      tablero[P.posY+1][P.posX]!=0;
           break;
      case 2:                        //ÜÜÜ
                                     // ß
           colision = tablero[P.posY][P.posX] != 0 ||
                      tablero[P.posY+1][P.posX+1] != 0 ||
                      tablero[P.posY][P.posX+2] != 0 ||
                      tablero[P.posY][P.posX+1]!=0;
           break;
      case 3:                        // ÜÛ
                                     //  ß
           colision = tablero[P.posY+1][P.posX] != 0 ||
                      tablero[P.posY+2][P.posX+1] != 0 ||
                      tablero[P.posY][P.posX+1]!=0 ||
                      tablero[P.posY+1][P.posX+1]!=0;
           break;
     }
    }

    /************/




 return colision;
}

/**********
 Este proceso se encarga de actualizar la pieza en la pantalla, e informar
 en caso de colision con otra pieza del tablero.
***********/
bool actualizaFicha(bool bajarFicha)
{
 bool colision;
 int alturaPieza, rot, x;
 pieza nuevaPosicionPieza;

 // Primero borramos la pieza anterior sobre el tablero
 // (esto se hace dibujandola del color de fondo).
 dibujaPieza( partidaActual.piezaActual, 0 );

 // Esta sera la nueva posicion de la pieza (en caso de no colision)
 nuevaPosicionPieza = partidaActual.piezaActual;
 // COLISION por la derecha FRUTO DE UNA ROTACION
 rot = nuevaPosicionPieza.rotacion;
 nuevaPosicionPieza.rotacion = nuevaPosicionPieza.proxRot;
 colision = ( ((nuevaPosicionPieza.posX+anchoPieza(nuevaPosicionPieza)) > ANCHO_TABLERO) );
 if ( colision == true )
 {
  nuevaPosicionPieza.proxRot = rot;
  nuevaPosicionPieza.rotacion = rot;
 }

 if ( bajarFicha == true )
  nuevaPosicionPieza.posY++;

 // Parece que intenta mover la pieza HORIZONTALMENTE
 if ( nuevaPosicionPieza.posX != nuevaPosicionPieza.proxX )
 {
  x = nuevaPosicionPieza.posX;
  nuevaPosicionPieza.posX = nuevaPosicionPieza.proxX;
  // Si el desplazamiento horizontal hace colisionar la pieza, se aborta este
  if ( piezaColisiona( partidaActual.tablero, nuevaPosicionPieza) )
   nuevaPosicionPieza.posX = x;
 }

 // Miramos si podemos bajar la pieza un punto hacia abajo.
 colision = piezaColisiona( partidaActual.tablero, nuevaPosicionPieza );

 // Si no hay colisi¢n, entonces actualizamos la posicion de la pieza
 if ( colision==false )
   partidaActual.piezaActual = nuevaPosicionPieza;

 // Finalmente dibujamos la pieza
 dibujaPieza( partidaActual.piezaActual, colorPieza(partidaActual.piezaActual) );

 return colision;
}

// Elegimos un color para cada tipo de pieza
int colorPieza(pieza P)
{
 return P.tipo+1;
}

// Esta funcion dibuja una figura al azar en el rectangulo definido
void  AnimaticaTimeSlice(void)
{
 static bool reiniciarTIMER = false;
 static clock_t s;
 static pieza p = obtenerPieza();

 if ( reiniciarTIMER == true )
 {
                 reiniciarTIMER = false;
                 s=clock();
 }

 if ( (clock()-s)/CLK_TCK > 0.1 )
 {
  dibujaPieza( p, 0 );
  p = obtenerPieza();
  p.posX = 16 + random(12);
  p.posY = 2 + random(5);
  dibujaPieza( p, random(15) );
  reiniciarTIMER = true;
 }

 /* REPRESENTO EL ESTADO ACTUAL DEL TABLERO
    /// HAY QUE SABER QUE HAY PARA VER SI TODO VA BIEN ////
  123456789012345
  60
  Üß Û
 */
 for (int i=0;i<ANCHO_TABLERO;i++)
  for (int j=0; j<ALTO_TABLERO;j++)
   { gotoxy( 60+i,2+j);
     textcolor(partidaActual.tablero[j][i]);
     cprintf("þ",partidaActual.tablero[j][i]);
   }

}


/////////////////////////////////////////////////////////////////////////
//////// ESTO SON SOLO CHORRADITAS DECORATIVAS PARA PERDER EL TIEMPO ////
/////////////////////////////////////////////////////////////////////////
void dibujaPiezaHUECA( pieza P, int color )
{
 int X, Y;
 X = P.posX*2+2;          // Coordenas iniciales para dibujar
 Y = P.posY+1;          // mas una correcci¢n visual (hay que encajar
                        // el tablero en la pantalla)

 textcolor(color);      // Establecemos el color de la pieza

 switch( P.tipo )
 {
  /*******************
     ROTACION 0    ROTACION 1    ROTACION 2    ROTACION 3
  *********************/

  //  ÛÛÛÛ           ÛÛÛÛ          ÛÛÛÛ          ÛÛÛÛ
  //  ÛÛÛÛ           ÛÛÛÛ          ÛÛÛÛ          ÛÛÛÛ
  case PIEZA_CUADRADA:
   switch( P.rotacion )
   {
    case 0:
    case 1:
    case 2:
    case 3:
         gotoxy(X,Y);   cprintf("ÚÄÄ¿");
         gotoxy(X,Y+1); cprintf("ÀÄÄÙ");
         break;
   }
   break;
  //  ÛÛ
  //  ÛÛ            ÛÛÛÛÛÛ        ÛÛÛÛÛÛ        ÛÛÛÛÛÛ
  //  ÛÛ
  case PIEZA_LINEA:
   switch( P.rotacion )
   {
    case 0:
    case 2:
         gotoxy(X,Y);   cprintf("Ú¿");
         gotoxy(X,Y+1); cprintf("³³");
         gotoxy(X,Y+2); cprintf("ÀÙ");
         break;
    case 1:
    case 3:
         gotoxy(X,Y);   cprintf("ÍÍÍÍÍÍ");
         break;
   }
   break;
  //                  ÛÛ                           ÛÛ
  //  ÛÛÛÛ          ÛÛÛÛ          ÛÛÛÛ           ÛÛÛÛ
  //    ÛÛÛÛ        ÛÛ              ÛÛÛÛ         ÛÛ
  case PIEZA_Rizq:
   switch( P.rotacion )
   {
    case 0:
    case 2:
         gotoxy(X,Y);         cprintf("ÍÍ¿¿");
         gotoxy(X+2,Y+1);       cprintf("ÀÀÍÍ");
         break;
    case 1:
    case 3:
         gotoxy(X+2,Y);         cprintf("Ú¿");
         gotoxy(X,Y+1);       cprintf("ÚÍÍÙ");
         gotoxy(X,Y+2);       cprintf("ÀÙ");
         break;
   }
   break;
  //                ÛÛ                           ÛÛ
  //   ÛÛÛÛ         ÛÛÛÛ            ÛÛÛÛ         ÛÛÛÛ
  // ÛÛÛÛ             ÛÛ          ÛÛÛÛ             ÛÛ
  case PIEZA_Rder:
   switch( P.rotacion )
   {
    case 0:
    case 2:
         gotoxy(X+2,Y)  ;       cprintf("ÚÚÍÍ");
         gotoxy(X,Y+1);       cprintf("ÍÍÙÙ");
         break;
    case 1:
    case 3:
         gotoxy(X,Y);         cprintf("Ú¿");
         gotoxy(X,Y+1);       cprintf("ÀÍÍ¿");
         gotoxy(X+2,Y+2);       cprintf("ÀÙ");
         break;
   }
   break;
  // ÛÛ                           ÛÛÛÛ
  // ÛÛ            ÛÛÛÛÛÛ           ÛÛ             ÛÛ
  // ÛÛÛÛ          ÛÛ               ÛÛ         ÛÛÛÛÛÛ
  case PIEZA_Lizq:
   switch( P.rotacion )
   {
    case 0:
         gotoxy(X,Y);       cprintf("Ú¿");
         gotoxy(X,Y+1);     cprintf("³³");
         gotoxy(X,Y+2);     cprintf("ÀÄÍÙ");
         break;
    case 1:
         gotoxy(X,Y);       cprintf("ÚÍÍÍÍÍ");
         gotoxy(X,Y+1);     cprintf("ÀÙ");
         break;
    case 2:
         gotoxy(X,Y);       cprintf("ÚÍÍ¿");
         gotoxy(X+2,Y+1);     cprintf("³³");
         gotoxy(X+2,Y+2);     cprintf("ÀÙ");
         break;
    case 3:
         gotoxy(X+4,Y);         cprintf("Ú¿");
         gotoxy(X,Y+1);     cprintf("ÍÍÍÍÍÙ");
         break;
   }
   break;
  //   ÛÛ                         ÛÛÛÛ
  //   ÛÛ          ÛÛ             ÛÛ           ÛÛÛÛÛÛ
  // ÛÛÛÛ          ÛÛÛÛÛÛ         ÛÛ               ÛÛ
  case PIEZA_Lder:
   switch( P.rotacion )
   {
    case 0:
         gotoxy(X+2,Y);       cprintf("Ú¿");
         gotoxy(X+2,Y+1);     cprintf("³³");
         gotoxy(X,Y+2);     cprintf("ÀÍÍÙ");
         break;
    case 1:
         gotoxy(X,Y);     cprintf("Ú¿");
         gotoxy(X,Y+1);   cprintf("ÀÍÍÍÍÍ");
         break;
    case 2:
         gotoxy(X,Y);     cprintf("ÚÍÍÍ");
         gotoxy(X,Y+1);   cprintf("³³");
         gotoxy(X,Y+2);   cprintf("ÀÙ");
         break;
    case 3:
         gotoxy(X,Y);       cprintf("ÍÍÍÍÍ¿");
         gotoxy(X+4,Y+1);       cprintf("ÀÙ");
         break;
   }
   break;
  //               ÛÛ                            ÛÛ
  //   ÛÛ          ÛÛÛÛ         ÛÛÛÛÛÛ         ÛÛÛÛ
  // ÛÛÛÛÛÛ        ÛÛ             ÛÛ             ÛÛ
  case PIEZA_T:
   switch( P.rotacion )
   {
    case 0:
         gotoxy(X+2,Y);      cprintf("É»");
         gotoxy(X,Y+1);    cprintf("ÍÍÊÊÍÍ");
         break;
    case 1:
         gotoxy(X,Y);       cprintf("Ú¿");
         gotoxy(X,Y+1);     cprintf("³ÌÍÍ");
         gotoxy(X,Y+2);     cprintf("ÀÙ");
         break;
    case 2:
         gotoxy(X,Y);       cprintf("ÍÍËËÍÍ");
         gotoxy(X+2,Y+1);     cprintf("ȼ");
         break;
    case 3:
         gotoxy(X+2,Y);       cprintf("Ú¿");
         gotoxy(X,Y+1);     cprintf("Í͹³");
         gotoxy(X+2,Y+2);     cprintf("ÀÙ");
         break;
   }
   break;
 }

}