/* Pepito v1.59  -- file: itera.c --
   Copyright (c) 2000-01 Carlos del Cacho

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; see the file COPYING.  If not, write to
   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.

   Contact the author: guggenjaimito@yahoo.com
*/

#ifndef UNIQUE_SOURCE_FILE
#  include "datos.h"
#endif


#ifdef CASTLE_STRIKE
#undef CASTLE_STRIKE
#endif

#define CASTLE_STRIKE     (UNIT_PROF/5)


#define GOOD_MOVE   1
#define BAD_MOVE    2

#define RWINDOW     (PEON_VAL/3)

list_jug *rpos_stack;
int RScore, RMat, SafetyFlags, easy_move, rply;

int Quiesce(int alpha, int beta, int prof, int ply);


int ALPHA, BETA, time_extend, text_count;


char            Pieza(int n)
{
    if (n > 6)
        n -= 6;

    if (!((1 << n) & (1|(1 << PEON_B)|(1 << PEON_N))))
        return piece_rep[n-1];
    else
        return 0;
}

//-------------------------------------------------------
int EstaAmenazado(int turno, int amenaza)
{
   return amenaza & (3 << (turno<<1));
}
//-------------------------------------------------------
int MantieneAmenaza(int turno, int amenaza)
{
   if (EstaAmenazado(turno, amenaza))
   {
     register int aux = 3 << (turno<<1);
     return ((amenaza & ~aux)|(aux & (aux-1))) & 0xf;
   }
   return amenaza & 0xf;
}
//-------------------------------------------------------
int PierdeUnaAmenaza(int turno, int amenaza)
{
   if (EstaAmenazado(turno, amenaza))
   {
       register int aux = 3 << (turno<<1);
       return (amenaza - aux) & 0xf;
   }
   return amenaza & 0xf;
}
//-------------------------------------------------------
int PierdeAmenazas(int turno, int amenaza)
{
   return amenaza & ~(3 << (turno<<1));
}
//-------------------------------------------------------
int IniAmenazas()
{
   return 10;
}

//------------------------------------------------------------------------
void PintaJugada(jugada_ext *ptrjug, void (*outfun)(char *fmt,...))
{
   int desde, hacia, esp;

   if (COORD_MODE)
   {
     PintaJugadaCoord(ptrjug->jug);
     return;
   }

   desde = ptrjug->jug & 0x3f;
   hacia = (ptrjug->jug >> 6) & 0x3f;
   esp = 3;

   if (ptrjug->pieza_mov == PEON_B || ptrjug->pieza_mov == PEON_N)
     if (!(ptrjug->jug & CAPTURA))
       esp = 4;

   switch (ptrjug->jug & 0xfff)
   {
     case (E1 | (G1 << 6)) : if (ptrjug->pieza_mov == REY_B) esp = 1; break;
     case (E1 | (C1 << 6)) : if (ptrjug->pieza_mov == REY_B) esp = 2; break;
     case (E8 | (G8 << 6)) : if (ptrjug->pieza_mov == REY_N) esp = 1; break;
     case (E8 | (C8 << 6)) : if (ptrjug->pieza_mov == REY_N) esp = 2; break;
   }

   switch (esp)
   {
     case 1: outfun("O-O"); break;
     case 2: outfun("O-O-O"); break;
     case 3: if (esp = Pieza(ptrjug->pieza_mov))
               outfun("%c",(char)esp);
             outfun("%c%d%c",'a' + MOD8(desde), 8 - DIV8(desde),
                             (ptrjug->jug & CAPTURA) ? 'x' : '-');
     default: outfun("%c%d", 'a' + MOD8(hacia), 8 - DIV8(hacia));
   }

   if (ptrjug->jug & PROMOCION)
     outfun("=%c",Pieza((ptrjug->jug >> 16) & 0xf));
     
   outfun(" ");
}

//------------------------------------------------------------------------
void PintaJugadaCoord(entero32 jug)
{
   int desde = jug & 0x3f;
   int hacia = (jug >> 6) & 0x3f;

   static char promop[] = { 0, 0, 'n', 'b', 'r', 'q', 0,
                               0, 'n', 'b', 'r', 'q', 0  };


   Print("%c%d%c%d",'a' + MOD8(desde), 8 - DIV8(desde),
                'a' + MOD8(hacia), 8 - DIV8(hacia));
                    
   if (jug & PROMOCION)
     Print("%c",promop[(jug >> 16) & 0xf]);

   Print(" ");
}

//------------------------------------------------------------------------
void Swap(list_jug *e1, list_jug *e2)
  {
    list_jug temp;

    temp = *e1;
    *e1 = *e2;
    *e2 = temp;

    return;
  }
//-----------------------------------------------------------------------
list_jug *SoloValidas(list_jug *limite)
{
     list_jug *i, *validas = JugStack;

     for (i = JugStack; i < limite; i++)
     {
        Mueve(i->jug);
        if (!Jaque(Turno))
           *(validas++) = *i;

        DesMueve();
     }

     return validas;
}
//-----------------------------------------------------------------------
list_jug *JugadasDeLibro(list_jug *limite)
{
     list_jug *i, *validas = limite;
     int bk_move;

     tab.have_book_move = 0;

     if (tab.book_retry)
     {
         if (!BookLoaded())
         {
            BookOpen(BOOK_FILE);
            if (!tab.book_retry)
                return limite;
         }

         for (i = JugStack; i < limite; i++)
         {
            Mueve(i->jug);
            CambiaTurno();

            bk_move = 0;
            i->valor = BookProbe(0);

            if (i->valor)
            {
               bk_move = 1;

               if (!tab.have_book_move)
               {
                   validas = JugStack;
                   tab.have_book_move = 1;
               }
            }

            CambiaTurno();
            DesMueve();

            if (bk_move)
               *(validas++) = *i;
         }

         if (!tab.have_book_move)
         {
            if (!tab.analyzing && !(--tab.book_retry))
               BookClose();
         }
     }

     return validas;
}
//-----------------------------------------------------------------------
int PreProcesa()
{
    const int *BKUP_TABLA_PEON = TABLA_PEON;

/* static int TABLA_MED[] =  {  0,  0,  0,  0,  0,  0,  0,  0,
                              9, 10, 10, 20, 20, 10, 10,  9,
                              4,  4, 10, 18, 18, 12,  4,  4,
                              3,  3,  8, 16, 16,  9,  3,  3,
                              2,  2, 10, 14, 14,  6,  2,  2,
                              1,  1,  6, 10, 10,  3,  1,  1,
                              0,  0,  3,  4,  4,  0,  0,  0,
                              0,  0,  0,  0,  0,  0,  0,  0 };
*/

 static int TABLA_MED[] =  {  0,  0,  0,  0,  0,  0,  0,  0,
                              9, 10, 10, 20, 20, 10, 10,  9,
                              4,  4, 10, 18, 18, 12,  4,  4,
                              2,  3,  8, 11, 11,  8,  3,  2,
                              1,  2,  6,  8,  8,  6,  2,  1,
                              0,  1,  2,  5,  5,  2,  1,  0,
                              0,  0,  3, -1, -1,  0,  0,  0,
                              0,  0,  0,  0,  0,  0,  0,  0 };


 static int TABLA_FIN[] =  {  0,  0,  0,  0,  0,  0,  0,  0,
                             16, 16, 16, 30, 30, 16, 16, 16,
                             12, 12, 12, 25, 25, 12, 12, 12,
                              9,  9, 10, 22, 22,  9,  9,  9,
                              6,  6,  7, 11, 11,  6,  6,  6,
                              3,  3,  1,  6,  6,  3,  3,  3,
                              0,  0,  0, -1, -1,  0,  0,  0,
                              0,  0,  0,  0,  0,  0,  0,  0 };

   int suma_peones = PopCnt(PeonesB | PeonesN);

   if(suma_peones > 8 && (PiezasB + PiezasN) > 7)
     TABLA_PEON = TABLA_MED;
   else if(suma_peones > 6 && (PiezasB + PiezasN) > 5)
     TABLA_PEON = TABLA_MED;
   else
     TABLA_PEON = TABLA_FIN;



   return (BKUP_TABLA_PEON != TABLA_PEON);
}

//-----------------------------------------------------------------------
void Itera(entero32 *eleccion, int ponder_on, entero32 time_limit, int *bk_flag)
  {
     list_jug *mejor_jug;
     long i;
     float tim;
     int n, amenazas;
     int ACTUAL, BEST, a, b;
     int out_of_window, pinta_pv;
     int first, egtb_conv = 0;
     int extension;
     long total_nods_iter;
     long NodsIter[MAX_PROF];
 
     double bfactor = 0;

     int fh_inrow, fl_inrow;

     MaxPos[0] = Max(PEON_VAL, MaxPos[0]>>1);
     MaxPos[1] = Max(PEON_VAL, MaxPos[1]>>1);
     pv_long[0] = 0;

     if (bk_flag)
       *bk_flag = NO_BOOK_MOVES;

     TimeReset();
     tab.time_up = 0;

     for (i=0;i<4096;i++)
     {
       tab.history[i][0] >>= 8;
       tab.history[i][1] >>= 8;
     }

     Historial[NumJug].depth = 0;

//     for (i=0;i<MAX_PROF;i++)
//       memset(tab.killer[i], 0, 2*sizeof(killer_type));

//     memset(tab.eval_cache, 0,CACHE_SIZE*sizeof(ecache));

     RTurno = Turno;
     SafetyFlags = 0;

     switch(GAME_STYLE)
     {
       case 0: SafetyFlags = 2 >> Turno; break;
       case 1: SafetyFlags = 0; break;
       case 2: SafetyFlags = 3; break;
     }

     tab.max_stack[0] = JugadasDeLibro(tab.max_stack[0]);

     if (tab.have_book_move && BOOK_RANDOM)
     {
        float rnd;
        int sum=0;
        jugada_ext j;

        if (bk_flag && (tab.max_stack[0]-JugStack) > 1)
            *bk_flag = SEVERAL_BOOK_MOVES;


        ShellSort(JugStack, tab.max_stack[0]);

        for(i=0, rpos_stack = tab.max_stack[0]-1; rpos_stack >= JugStack && i < BOOK_WIDTH; rpos_stack--, i++)
          sum += rpos_stack->valor;

        Print("0 0 0 0 ");

        for(i=0, rpos_stack = tab.max_stack[0]-1; rpos_stack >= JugStack && i < BOOK_WIDTH; rpos_stack--, i++)
        {
           j.jug = rpos_stack->jug;
           j.pieza_mov = Tablero[j.jug & 0x3f];
           PintaJugada(&j, Kibitz);
           Kibitz("(%.2f %%) ", (double)rpos_stack->valor*100/sum);
        }
        Kibitz("\n");

        rnd = (float)sum*rand()/RAND_MAX;
        sum = (tab.max_stack[0]-1)->valor;

        for(i=0, rpos_stack = tab.max_stack[0]-1; sum < rnd && rpos_stack > JugStack && i < BOOK_WIDTH; rpos_stack--, i++)
           sum += rpos_stack->valor;

        *eleccion = rpos_stack->jug;
        tab.my_bk_limit = NumJug;

        return;
     }

     if (tab.max_stack[0] == (JugStack+1) && !ponder_on)
     {
        *eleccion = JugStack->jug;
        return;
     }


     if (PreProcesa())
     {
       memset(tab.trans_tab_p, 0, PAWN_HASH_SIZE*sizeof(entrada_hash_p));
       for (i=0;(unsigned)i<HASH_SIZE;i++)
       {
         tab.trans_tab[i].high = ENTRADA_VIEJA;
         tab.trans_tab[i].low = 0;
       }
     }
     else
       for (i=0;(unsigned)i<HASH_SIZE;i++)
         tab.trans_tab[i].high |= ENTRADA_VIEJA;

     tab.nodos_buscados = 0;
     tab.nodos_quies = 0;

     tab.null_attempts = 0;
     tab.null_cuts = 0;
     tab.hash_hits = 0;
     tab.hash_used = 0;
     tab.p_hash_trys = 0;
     tab.p_hash_hits = 0;
     tab.fut_cuts = 0;
     tab.nodos_control = CONTROL_INC;
     tab.last_report = 0;
     if (time_limit < 200)
       tab.nodos_control = 2000;
     tab.nodos_buscados = 0;
     tab.first_succ = 0;
     tab.beta_cutoffs = 0;
     tab.internal_iter=0;
     tab.chk_extensions = 0;
     tab.moreland_extensions = 0;
     tab.recap_extensions = 0;
     tab.pondering = ponder_on;
     tab.time_limit = time_limit;
     tab.egtb_probes = 0;
     tab.egtb_hits = 0;
     tab.evals = 0;
     tab.eval_hits = 0;
     tab.lazy_evals = 0;

START_OF_THINKING:

     ALPHA = -INFINITO;
     BETA = INFINITO;

     total_nods_iter = 0;

     for(rpos_stack = tab.jug_stack; rpos_stack < tab.max_stack[0]; rpos_stack++)
     {
       rpos_stack->valor = SSE(rpos_stack->jug);
       Mueve(rpos_stack->jug);
       CambiaTurno();
       tab.jaque[1] = Jaque(Turno);
       rpos_stack->valor = -Quiesce(-INFINITO,INFINITO, UNIT_PROF,1);
       CambiaTurno();
       DesMueve();
     }
     ShellSort(tab.jug_stack, tab.max_stack[0]);
     RMat = TBalance;

     easy_move = 0;
     if (((tab.max_stack[0]-1)->valor -2*PEON_VAL)> (tab.max_stack[0]-2)->valor)
     {
       if (((tab.max_stack[0]-1)->jug & CAPTURA && RMat < -PEON_VAL)
           || !((tab.max_stack[0]-1)->jug & CAPTURA))
         easy_move = xb_info.my_clock && !ponder_on;
     }

     MaxProf = 2*UNIT_PROF;
     rply = 2;

     if (ProbeHash(&(tab.max_stack[0]->jug),&BEST,&ACTUAL,&b,&a))
     {
                if (b == EXACTO && tab.max_stack[0]->jug)
        for(rpos_stack = tab.jug_stack; rpos_stack < tab.max_stack[0]; rpos_stack++)
	       if (rpos_stack->jug == tab.max_stack[0]->jug)
		   {
                     if (ACTUAL > MaxProf)
                        MaxProf = ACTUAL - (ACTUAL%UNIT_PROF);
                     rply = MaxProf/UNIT_PROF;
                     BETA = BEST + PEON_VAL/2;
                     ALPHA = BEST - PEON_VAL/2;
                     pv[0][0].jug = rpos_stack->jug;
                     Swap(rpos_stack,tab.max_stack[0]-1);
                     break;
		   }
         }

     BEST = -INFINITO;

     if (Nalimov && (NumPeonesB + NumPeonesN + PiezasB + PiezasN) <= (Nalimov - 2) &&
         (ACTUAL = ProbeTB(0)) != -1)
     {
        egtb_conv = ACTUAL > 0 ? ACTUAL+1 : 0;
     }

     RScore = (tab.max_stack[0]-1)->valor;

     time_extend = 0;
     text_count = 0;

     for (;MaxProf <= MAXPROF && (BEST < 9000 || BEST > 11000 || tab.analyzing); MaxProf += UNIT_PROF, rply++)
       {
          out_of_window = 1;
          total_nods_iter =  tab.nodos_buscados;// + tab.fut_cuts;
          fh_inrow = 0, fl_inrow = 0;

          while (out_of_window)
          {
              first = 1;
              pinta_pv = 0;
              a = ALPHA;
              b = BETA;
              BEST = -INFINITO;

              for(rpos_stack = tab.max_stack[0]-1; rpos_stack >= tab.jug_stack; rpos_stack--)
              {   
                  if (UCI_MODE && (tab.nodos_buscados) > 140000)
                  {  
                     Print("info currmove ");
                     PintaJugadaCoord(rpos_stack->jug);
                     Print("currmovenumber %d\n",tab.max_stack[0]-rpos_stack);
                  }


                  tab.nodos_jug_raiz = tab.nodos_buscados + tab.fut_cuts;
                  Mueve(rpos_stack->jug);
                  CambiaTurno();

                  extension = -UNIT_PROF + UNIT_PROF*(tab.jaque[1] = Jaque(Turno));
                  tab.extensiones[1] = 0;

#if CASTLE_STRIKE

                  if (Turno)
                  {
                     if (((rpos_stack->jug & CAPTURA) >> 12) == PEON_B)
                     {
                        int hacia = (rpos_stack->jug >> 6) & 0x3f;

                        if (PosStatus & REY_B_ENRQ_CORTO && 
                            MASK[hacia] & WSCASTLEZONE)
                          tab.extensiones[1] |= TRIGGER_CSTRIKE;
                        else if (PosStatus & REY_B_ENRQ_LARGO && 
                            MASK[hacia] & WLCASTLEZONE)
                          tab.extensiones[1] |= TRIGGER_CSTRIKE;
                     }
                  }
                  else
                  {
                     if (((rpos_stack->jug & CAPTURA) >> 12) == PEON_N)
                     {
                        int hacia = (rpos_stack->jug >> 6) & 0x3f;

                        if (PosStatus & REY_N_ENRQ_CORTO && 
                            MASK[hacia] & BSCASTLEZONE)
                          tab.extensiones[1] |= TRIGGER_CSTRIKE;
                        else if (PosStatus & REY_N_ENRQ_LARGO && 
                            MASK[hacia] & BLCASTLEZONE)
                          tab.extensiones[1] |= TRIGGER_CSTRIKE;
                     }
                  }
#endif

                  pv_long[1] = 1;
                  if (Repeticion(0))
                    ACTUAL = TABLAS;
                  else
                  {
                    amenazas = IniAmenazas();
                    if (!tab.jaque[1] && !(rpos_stack->jug & (CAPTURA|PROMOCION)))
                      amenazas = PierdeUnaAmenaza(Turno, amenazas);


                    ACTUAL = -NegaScout(-b,-a, MaxProf+extension,1,1,amenazas);
                    if ((ACTUAL > a) && (ACTUAL < BETA) && !first && !tab.time_up)
                    {
//                      jugada_ext j;
//                      Print("%2d %5d %5d %8d  ", MaxProf/UNIT_PROF, ACTUAL,TimeDiff(),
//                                 tab.nodos_buscados);
//                      j.jug = rpos_stack->jug;
//                      j.pieza_mov = Tablero[(j.jug>>6) & 0x3f];
//                      PintaJugada(&j, Print);
//                      Print("!?\n");
                      time_extend |= 1;
                      easy_move = 0;
                      ACTUAL = -NegaScout(-BETA,-a, MaxProf+extension,1,1,amenazas);
                      time_extend &= (time_extend - 1);
                    }
                    if (egtb_conv> 9000 && ACTUAL == egtb_conv)
                      egtb_conv = Nalimov;
                  }

                  CambiaTurno();
                  DesMueve();

                  if (tab.time_up)
		            goto END_OF_THINKING;


                  rpos_stack->valor = tab.nodos_jug_raiz;
                  if (xb_info.post || UCI_MODE)
                    pinta_pv |= (MaxProf >= DISPLAY_MARGIN);

                  if (ACTUAL > a)
                  {
                        Historial[NumJug].score = ACTUAL;
                        Historial[NumJug].depth = rply;

/*                      if (ACTUAL < BETA)
                      {
                         Mueve(rpos_stack->jug);
                         CambiaTurno();
 
                         for (i=1;i<pv_long[1] && pv[1][i].jug ;i++)
                         {
                           Mueve(pv[1][i].jug);
                           CambiaTurno();
                         }

                         tab.jaque[i+1] = Jaque(Turno);
                         tab.extensiones[i+1] = 0;
                         tab.max_stack[i] = tab.max_stack[0];

                         if (Turno == RTurno)
                           n = Quiesce(a, BETA, UNIT_PROF,i+1);
                         else
                           n = -Quiesce(-BETA, -a, UNIT_PROF,i+1);

                         for (;i;i--)
                         {
                            CambiaTurno(); 
                            DesMueve(); 
                         }

                         if (n == ACTUAL)
                           printf("Coinciden :-)\n");
                         else printf("No Coinciden :-(\n");
                      }*/


//                    pinta_pv &= (int) (rpos_stack->jug != pv[0][0].jug);
                      pv_long[0] = pv_long[1];
                      if (pv[0][0].jug != rpos_stack->jug)
                      {
                         pv[0][0].jug = rpos_stack->jug;
                         time_extend = 1;
                      }
                      pv[0][0].pieza_mov = Tablero[rpos_stack->jug  & 0x3f];
                      mejor_jug = rpos_stack;
                      for (i=1; i < pv_long[1]; i++)
                      {
                         pv[0][i].jug = pv[1][i].jug;
                         pv[0][i].pieza_mov = pv[1][i].pieza_mov;
                      }

                      if (pinta_pv)
                      {
                         if (UCI_MODE)
                         {
                           unsigned long tiempo = TimeDiff();

                           Print("info score ");

                           if (ACTUAL > JAQUE_MATE-1000)
                               Print("mate %d ", (JAQUE_MATE-ACTUAL+1)/2);
                           else if (ACTUAL < -JAQUE_MATE+1000)
                               Print("mate %d ", (-JAQUE_MATE-ACTUAL)/2);
                           else
                               Print("cp %d ", ACTUAL);
                           
                           Print("%s depth %d nodes %d time %d nps %d hashfull %d tbhits %d pv ",
                                 ACTUAL >= BETA? "lowerbound" : "",MaxProf/UNIT_PROF,
                                 tab.nodos_buscados,
                                 tiempo*10, 100*(tab.nodos_buscados)/tiempo,
                                 (unsigned)(1000*((double)tab.hash_used/HASH_SIZE)),
                                 tab.egtb_hits);
                         }
                         else
                           Print("%2d %5d %5d %8d  ", MaxProf/UNIT_PROF, ACTUAL,TimeDiff(),
                                 tab.nodos_buscados);
                         PintaJugada(&pv[0][0], Print);
                         if ( ACTUAL >= BETA && !UCI_MODE)
                           Print("!! ");

                         for (i=1;i<pv_long[0];i++)
                            PintaJugada(&pv[0][i], Print);
                         Print("\n");
                       }
                             
                       if ( ACTUAL >= BETA )
                       {
                           time_extend = 1;
                           if (!fh_inrow)
                           {
                              b = BETA = ACTUAL + PEON_VAL;
                              fh_inrow = 1;
                           }
                           else
                              b = BETA = INFINITO;

                           if (!(rpos_stack->jug & (CAPTURA|PROMOCION)) && !(tab.jaque[0]))
                              tab.history[rpos_stack->jug & 0xfff][Turno] += 1+(MaxProf*MaxProf)/(UNIT_PROF*UNIT_PROF);

                           first = 1;
                           rpos_stack++;
                           continue;         //  fail high
                        }
                        a = BEST = ACTUAL;
                        ALPHA = BEST - RWINDOW;
                        BETA  = BEST + RWINDOW;
                  }
                  else if (first)
                  {
                     a = ALPHA = ACTUAL;
                     time_extend = 3;
                     easy_move = 0;
                  }
                  b = a + 1;
                  first = 0;
               }

               total_nods_iter = tab.nodos_buscados /*+ tab.fut_cuts*/ - total_nods_iter;
               NodsIter[-1 + MaxProf / UNIT_PROF] = tab.nodos_buscados + tab.fut_cuts;

               total_nods_iter = tab.nodos_buscados /*+ tab.fut_cuts*/ - total_nods_iter;

               if (pinta_pv)
               {
                 if (UCI_MODE)
                 {
                    Print("info score ");

                    if (a > JAQUE_MATE-1000)
                       Print("mate %d ", (JAQUE_MATE-a+1)/2);
                    else if (a < -JAQUE_MATE+1000)
                       Print("mate %d ", (-JAQUE_MATE-a)/2);
                    else
                       Print("cp %d ", a);

                    Print("%s depth %d nodes %d time %d tbhits %d pv ",
                           a==ALPHA? "upperbound" : "" ,MaxProf/UNIT_PROF,
                           tab.nodos_buscados,TimeDiff()*10,tab.egtb_hits);
                 }
                 else
                    Print("%2d %5d %5ld %8ld  ", MaxProf/UNIT_PROF, a,TimeDiff(),tab.nodos_buscados);
                 PintaJugada(&pv[0][0], Print);
                 if (a == ALPHA && !UCI_MODE)
                   Print("?? ");
                 for (i=1;i<pv_long[0];i++)
                   PintaJugada(&pv[0][i], Print);
                 Print("\n");
               }
               RScore = a;
               if (a == ALPHA)
               {
                    Historial[NumJug].score = ALPHA;
                    Historial[NumJug].depth = rply;
                    time_extend = 3;
                    easy_move = 0;
                    if (!fl_inrow)
                    {
                       BETA = ALPHA+1;
                       ALPHA -= PEON_VAL;
                       fl_inrow = 1;
                    }
                    else
                    {
                       BETA = ALPHA+1;
                       ALPHA = -INFINITO;
                    }

                    first = 1;
                 }
                 else
                 {
                    time_extend &= (time_extend-1);
                    if (!(mejor_jug->jug & (CAPTURA|PROMOCION)) && !tab.jaque[0])
                      tab.history[mejor_jug->jug & 0xfff][Turno] += 1+(MaxProf*MaxProf)/(UNIT_PROF*UNIT_PROF);

                    out_of_window = 0;

                    Swap(mejor_jug,tab.max_stack[0]-2);
                    Swap(tab.max_stack[0]-2,tab.max_stack[0]-1);

 	            LastProf = MaxProf-UNIT_PROF;

                    for (i=0;i<pv_long[0] && pv[0][i].jug ;i++,LastProf -= UNIT_PROF)
                    {
                      int val;
                      if (!ProbeHash(&(tab.max_stack[0]->jug),&val,&ACTUAL,&val,&val))
                      {
                        StuffHash(pv[0][i].jug, BEST, Max(0,LastProf), EXACTO, 0, 0);
                        BEST = -BEST;
                      }
                      Mueve(pv[0][i].jug);
                      CambiaTurno();
                    }

                    for (;i;i--)
                    {
                       CambiaTurno(); 
                       DesMueve(); 
                    }
                    BEST = ALPHA + RWINDOW;

                    tim = (float) TimeDiff();
                    if (tim > 2*tab.time_limit/3 && !time_extend && xb_info.my_clock)
                       goto END_OF_THINKING;

                    ShellSort(JugStack, tab.max_stack[0]-2);
                 }
            }  // jugadas raiz

       }   // fin jugadas raiz

END_OF_THINKING:


if (egtb_conv)
{
   if (egtb_conv > 9000)
   {
      Log("Faltan EGTBs! Probando busqueda sin Nalimov... %d\n",egtb_conv);
      egtb_conv = Nalimov;
      Nalimov = 0;
      ClearTables(0);
      goto START_OF_THINKING;
   }
   else
     Nalimov = egtb_conv;
}

if (xb_info.my_clock && BETA < RESIGN_MARGIN)
 tab.time_up = 3;

{
	double eratio;
     Log("\nTime spent: %0.2f\n",  tim = ((float)TimeDiff())/100);

     for (n = 1; n < MaxProf/UNIT_PROF - 1; n++)
       bfactor += (NodsIter[n-1] ? NodsIter[n] / NodsIter[n-1] : 0);
     bfactor /= (MaxProf/UNIT_PROF -2);

     if (rpos_stack - tab.jug_stack > 0)
       Log("Depth reached: %0.3f\n",MaxProf/UNIT_PROF-1+(float)(rpos_stack - tab.jug_stack)
                                                        /(tab.max_stack[0] - tab.jug_stack));
     else
       Log("Depth reached: %d\n",MaxProf/UNIT_PROF-1);

     Log("Nodes per second: %0.8f\n",(double) (tab.nodos_buscados)/tim);
     Log("Interior nodes: %ld\n",tab.nodos_buscados-tab.nodos_quies);
     Log("Quiescent nodes: %ld\n",tab.nodos_quies);

     Log("First_success: %ld/%ld  (%0.3f %%).\n",tab.first_succ,tab.beta_cutoffs,
             100*( (double) tab.first_succ / tab.beta_cutoffs ));
     Log("BranchingFactor: %0.3f\n",bfactor);
     Log("Null-moves: %ld/%ld  (%0.3f %%).\n",tab.null_cuts,tab.null_attempts,
             100*( (double) tab.null_cuts/tab.null_attempts));
     Log("Hash hits: %ld/%ld  (%0.3f %%).\n",tab.hash_hits,tab.nodos_buscados-tab.nodos_quies,
             100*( (double) tab.hash_hits / (tab.nodos_buscados-tab.nodos_quies)));
	 eratio = tab.egtb_probes > 0? 100*( (double) tab.egtb_hits / tab.egtb_probes) : 0;
     Log("EGTB hits: %ld/%ld  (%0.3f %%).\n",tab.egtb_hits,tab.egtb_probes, eratio);
     Log("Pawn Hash hits: %ld/%ld  (%0.3f %%).\n",tab.p_hash_hits,tab.p_hash_trys,
             100*( (double) tab.p_hash_hits / tab.p_hash_trys));
     Log("Futility cut-offs: %ld.\n",tab.fut_cuts);
     Log("IID: %ld.\n",tab.internal_iter);
     Log("Evals:  %ld.  Lazy:  %ld. (%0.3f %%). Cached:   %ld. (%0.3f %%).\n",
		     tab.evals, tab.lazy_evals, 100*( (double) tab.lazy_evals / tab.evals),
                         tab.eval_hits, 100*((double) tab.eval_hits / (tab.evals-tab.lazy_evals)));

     Log("Extensions:   CHK  %ld.  MRL  %ld.  RCP  %ld.\n",
             tab.chk_extensions, tab.moreland_extensions,tab.recap_extensions);

     Log("MaxPosB:   %d, MaxPosN: %d\n",MaxPos[0],MaxPos[1]);


/*     Log("Move ordering ratio:\n");
     for (i=0;i<80;i++)
      if (tab.fail_high_record[i])
        Log("%2d. %8d times (%5.3f)\n",i+1,tab.fail_high_record[i],
              100*(double) tab.fail_high_record[i] / tab.beta_cutoffs);
*/
}
     *eleccion = pv[0][0].jug;
     Historial[NumJug].time  = TimeDiff()/100;

     if (ICS_MODE)
     {
        Kibitz("depth: %d  time: %ds  NPS: %d  score: %d  PV: ",
                Historial[NumJug].depth,
                Historial[NumJug].time,
                (tab.nodos_buscados)/tim,
                Historial[NumJug].score);

        for (i=0;i<pv_long[0];i++)
            PintaJugada(&pv[0][i], Kibitz);
        Kibitz("\n");
     }
  }
//----------------------------------------------------------------------------
void EvalTest(int xb_mode)
{
   char *tellstr = xb_mode ? "telluser " : "";
   Print("\n%sstm: %s", tellstr, Turno? "White" : "Black");
   RTurno = 1;
   PreProcesa();
   ClearTables(0);

   SafetyFlags = 0;

   switch(GAME_STYLE)
   {
       case 0: SafetyFlags = 2 >> Turno; break;
       case 1: SafetyFlags = 0; break;
       case 2: SafetyFlags = 3; break;
   }

   Print("%sscore (comp white): %6.2f",xb_mode ? ";  " : "\n",(double)Evaluacion(-INFINITO, INFINITO)/100);
   RTurno = 0;
   PreProcesa();
   ClearTables(0);
   Print("%sscore (comp black): %6.2f\n\n",xb_mode ? ";  " : "\n",(double)Evaluacion(-INFINITO, INFINITO)/100);
/*   for(pos_stack = tab.jug_stack; pos_stack < tab.max_stack[0]; pos_stack++)
   {
     Mueve(pos_stack->jug);
     CambiaTurno();
     pos_stack->valor = -Evaluacion(-INFINITO, INFINITO);
     CambiaTurno();
     DesMueve();
   }
   ShellSort(tab.jug_stack, tab.max_stack[0]);

   for(i = 0, pos_stack = tab.max_stack[0]-1; pos_stack >= JugStack && i < 5; pos_stack--,i++)
   {
      Print("%2d.  ",tab.max_stack[0]-pos_stack);
      j.jug = pos_stack->jug;
      j.pieza_mov = Tablero[j.jug & 0x3f];
      Print("%6.2f   ", (double)pos_stack->valor/100);
      PintaJugada(&j, Print);
      Print("\n");
   }*/
}


