/**************************************************************************\
|*                                                                          *|
|*  4 en Raya                                                               *|
|*                                                                          *|
|*  Algoritmo de combate dise¤ado por JD, capaz de profundizar en           *|
|*  jugadas defensivas/ofensivas.                                           *|
|*                                                                          *|
|*                                                                          *|
|*                                                                          *|
 \**************************************************************************/

 #include <mem.h>

 char Tablero[7][7]; // [FILA][COLUMNA]

 #define TAMANYO_DEL_TABLERO  7*7
 #define ANCHO_TABLERO          7
 #define ALTO_TABLERO           3

 #define NO_HAY_NADIE           0
 #define JUGADOR1               1
 #define JUGADOR2               2

 #define PROFUNDIDAD_DE_JUEGO   5

 class Conecta4
 {
  private:
          char StatusError;
          char QuienSoy;
          char *TableroOriginal;
          char *CopiaDelTablero;

          char AveriguaQuienSoy(void);
          char GanaTurno( int *Pos_x, int *Pos_y, char JUGADOR_DUMMY );
          void AlgInteligente( int *Pos_x, int *Pos_y, char JUGADOR_DUMMY );


  public:

          Conecta4(char *DirTablero);
         ~Conecta4();

         void JuegaTurno(void);
         char *Error(void);
 };

 void Conecta4::JuegaTurno( void )
 {
  int x, y;                             // Punto, donde pondr‚ mi ficha
  int X, Y;                             // Puntos de avance en el tiempo.
  char Enemigo;
  char ok, Turno;

  // ¨ Quien soy YO ?
  if ( QuienSoy == -1 )
   AveriguaQuienSoy();

  if ( QuienSoy == JUGADOR1 )
   Enemigo = JUGADOR2;
  else
   Enemigo = JUGADOR1;

  // Realizamos una copia del Tablero para las profudizaciones
  memcpy( CopiaDelTablero, Tablero, sizeof( char ) * (TAMANYO_DEL_TABLERO) );

  // ¨ Podemos ganar en este turno ?
  if ( GanaTurno( &x, &y, QuienSoy ) )
  {
   *( TableroOriginal + ANCHO_TABLERO*y + x ) = QuienSoy;
   return;
  }

  // ¨ Tengo que defender en este turno ?
  if ( GanaTurno( &x, &y, Enemigo ) )
  {
   *( TableroOriginal + ANCHO_TABLERO*y + x ) = QuienSoy;
   return;
  }

  ok = 0; Turno = 0;
  // Tengo libertad en este turno para colocar la ficha donde quiera...
  do {

   AlgInteligente( &x, &y, QuienSoy );

   // Me adelanto en el tiempo para ver que pasa si pongo la ficha hay...
   // --------- OK == 0 JUGADA MALA :::: OK == 1 JUGADA BUENA -----------

   // -- ¨ Tengo mas lugares donde poner ? (si esta jugada no es buena)
   if ( Turno > (ANCHO_TABLERO*ALTO_TABLERO) )
   {
    // ­­ Que le vamos hacer !!, puede ganar el contrario
    ok = 1;
   } else {
    // Si pongo aqui: ¨ Gana el siguiente turno el enemigo ?  1==NO :: 0==SI
    if ( (ok = !GanaTurno( &X, &Y, Enemigo ) ) )
    {
     // Vale, el enemigo no ganar  en el siguiente turno, pero...
     //     ...que tal si nos adelantamos un poquito en el tiempo.
     AlgInteligente( &X, &Y, Enemigo );
     *( CopiaDelTablero + ANCHO_TABLERO*Y + X ) = Enemigo;
     // Ahora juego yo...
     if ( GanaTurno( &X, &Y, QuienSoy ) )
     {
      // Vale tengo asegurado el ganar dos turnos mas hacia adelante.
      ok = 1;
     } else {
      // Dentro de dos turnos no gano, pero...
      AlgInteligente( &X, &Y, QuienSoy );
      *( CopiaDelTablero + ANCHO_TABLERO*Y + X ) = QuienSoy;
      //                                      ...¨y el enemigo?
      if ( GanaTurno( &X, &Y, Enemigo ) )
      {
       // Parece que el enemigo gana, y no me la va a dar, asi de facil.
       ok = 0;
      } else {
       // Juega mejor colega, por que a mi no me ganas.
       ok = 1;
      }
     }
    }
   }
   Turno++;
  } while ( !ok );

  // Este el el punto de inserci¢n optimo.
  *( TableroOriginal + ANCHO_TABLERO*y + x ) = QuienSoy;

 }


 // Comprobamos si el JUGADOR_DUMMY puede ganar este turno (Dev: Pos ganadora)
 char Conecta4::GanaTurno( int *Pos_x, int *Pos_y, char JUGADOR_DUMMY )
 {
   int i, j, k;
   int Lug_X, FichasHints;
   char QueHay;

   int Pos_Y[ANCHO_TABLERO];

   // Posibles lugares donde meter la ficha
   for ( i = 0; i < ANCHO_TABLERO; i++ )
   {
    // Por defecto, no es posible usar esta columna...
    Pos_Y[i] = -1;
    for ( j = 0; j < ALTO_TABLERO; j++ )
    {
     if ( *( CopiaDelTablero + j * ANCHO_TABLERO + i ) == NO_HAY_NADIE )
     {
      Pos_Y[i] = j;
      break;
     }
    }
   }
   // Si metemos la ficha en algun lugar, ¨ GANAMOS ?
   FichasHints = 0;

   for ( i = 0; i < ANCHO_TABLERO; i++ ) // Revisamos todos los huecos
   if ( Pos_Y[i] != -1 )
   {
    //°²Û                                                  X
    //°²Û ¨ Posibilidad de ganar en HORIZONTAL ?           X X
    //°²Û                                                  X * * - *
    //°²Û                     Insertando la ficha gano ----------^
    for ( j = i-1; j>=0; j--)
    {
     QueHay = *( CopiaDelTablero + Pos_Y[i] * ANCHO_TABLERO + j );
     if ( QueHay == JUGADOR_DUMMY )
      FichasHints++;
     else break;
    }
    for ( j = i+1; j<ANCHO_TABLERO; j++)
    {
     QueHay = *( CopiaDelTablero + Pos_Y[i] * ANCHO_TABLERO + j );
     if ( QueHay == JUGADOR_DUMMY )
      FichasHints++;
     else break;
    }
    // Bingo, Aqui ganamos
    if ( FichasHints >= 3 )
    {
       *Pos_x = i;
       *Pos_y = Pos_y[i];
       return 1;
    }

    //°²Û                    Insertando la ficha gano ---> -
    //°²Û                                                  *
    //°²Û ¨ Posibilidad de ganar en VERTICAL ?             * X
    //°²Û                                                  * * X X X

    // Solo es posible si mi altura actual es >= 3
    if ( Pos_Y[i] >= 3 )
    {
      for ( j = Pos_Y[i]-1; j >= 0; j-- )
      {
       QueHay = *( TableroOriginal + Pos_Y[i] * ANCHO_TABLERO + i );
       if ( QueHay == JUGADOR_DUMMY )
        FichasHints++;
       else break;
      }
      if ( FichasHints >= 3 )
      {
       *Pos_x = i;
       *Pos_y = Pos_y[i];
       return 1;
      }
    }

    //°²Û                    Insertando la ficha gano ÄÄÄÄÄÄÄÄÄ¿ *
    //°²Û                                                  *   - * X
    //°²Û ¨ Posibilidad de ganar en DIAGONAL 1 ?           X * X X X
    //°²Û                                                  * * X X X
    k = i - 1;
    for ( j = Pos_Y[i]-1; j >= 0 && k >= 0; j--, k-- )
    {
     QueHay = *( CopiaDelTablero + j * ANCHO_TABLERO + k );
     if ( QueHay == JUGADOR_DUMMY )
      FichasHints++;
     else break;
    }
    k = i + 1;
    for ( j = Pos_Y[i]+1; j<ALTO_TABLERO && k < ANCHO_TABLERO; j++, k++ )
    {
     QueHay = *( CopiaDelTablero + j * ANCHO_TABLERO + k );
     if ( QueHay == JUGADOR_DUMMY )
      FichasHints++;
     else break;
    }
    // Bingo, Aqui ganamos
    if ( FichasHints >= 3 )
    {
       *Pos_x = i;
       *Pos_y = Pos_y[i];
       return 1;
    }

    //°²Û                    Insertando la ficha gano ÄÄÄÄÄÄÄ*Ä¿ X
    //°²Û                                                  X X - X X
    //°²Û ¨ Posibilidad de ganar en DIAGONAL 2 ?           X * X * X
    //°²Û                                                  X * * X *
    k = i + 1;
    for ( j = Pos_Y[i]-1; j >= 0 && k < ANCHO_TABLERO; j--, k++ )
    {
     QueHay = *( CopiaDelTablero + j * ANCHO_TABLERO + k );
     if ( QueHay == JUGADOR_DUMMY )
      FichasHints++;
     else break;
    }
    k = i - 1;
    for ( j = Pos_Y[i]+1; j<ALTO_TABLERO && k >= 0; j++, k-- )
    {
     QueHay = *( CopiaDelTablero + j * ANCHO_TABLERO + k );
     if ( QueHay == JUGADOR_DUMMY )
      FichasHints++;
     else break;
    }
    // Bingo, Aqui ganamos
    if ( FichasHints >= 3 )
    {
       *Pos_x = i;
       *Pos_y = Pos_y[i];
       return 1;
    }
   }

  // Este turno no puede ser ganado, DIRECTAMENTE!!!
  return 0;
 }

 // El algoritmo inteligente es el nucleo de pensamiento de mi OBJETO
 // decidir  cual es la posici¢n mas acertada, (EN EL TURNO ACTUAL), para
 // ganar la partida...
 //
 //  Partimos del supuesto que no nos es posible ganar directamente en este
 // turno y al enemigo tan poco le es posible en el siguiente. Por lo cual,
 // tenemos un total de ANCHO_TABLERO casillas donde poner nuestra ficha.
 //
 //  Actualmente, solo compruebo la frecuencia de aparici¢n de fichas, en
 // la media luna de posiciones que me rodean. FREC_MAX -> max. pos. de ganar.
 //
 //  Realmente en este algoritmo, se podr¡an tener algunas jugadas estrat‚gicas
 // ya prefijadas. Despues de jugar unas cuantas partidas con un HUMANO, nos
 // daremos cuenta que solo existen unas Xx jugadas estrategicas que se basan,
 // como mucho, en dos turnos adelante en el tiempo, de aqui mi control de
 // estos dos turnos en el tiempo...
 //                                           Fdo:
 //                                                Jose-David.Guillen@cs.us.es
 void Conecta4::AlgInteligente( int *Pos_x, int *Pos_y, char JUGADOR_DUMMY )
 {
 }


 Conecta4::Conecta4(char *DirTablero)
 {
  StatusError =  0;
  QuienSoy    = -1;

  TableroOriginal = DirTablero;
  if ( ( CopiaDelTablero = new char [TAMANYO_DEL_TABLERO] ) == NULL )
   StatusError = 1;
 }

 Conecta4::~Conecta4()
 {
  delete [] CopiaDelTablero;
 }

 char *Conecta4::Error(void)
 {
  char *MensajesError[40] = { "No hay suficiente Memoria",
                              "No quedan huecos libres",
                              "Error Desconocido" };

  if ( StatusError )
    return MensajesError[StatusError];
  else
    return NULL;
 }