#include "chess.h"
 
#include "data.h"
 
/* last modified 05/15/14 */
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   NextEvasion() is used to select the next move from the current move list  *
 
 *   when the king is in check.  We use GenerateEvasions() (in movgen.c) to    *
 
 *   generate a list of moves that get us out of check.  The only unusual      *
 
 *   feature is that these moves are all legal and do not need to be vetted    *
 
 *   with the usual Check() function to test for legality.                     *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
int NextEvasion(TREE * RESTRICT tree, int ply, int wtm) {
 
  int *movep, *sortv;
 
 
 
  switch (tree->next_status[ply].phase) {
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  First try the transposition table move (which might be  *
 
 *  the principal variation move as we first move down the  *
 
 *  tree).  If it is good enough to cause a cutoff, we      *
 
 *  avoided the overhead of generating legal moves.         *
 
 *                                                          *
 
 ************************************************************
 
 */
 
    case HASH_MOVE:
 
      if (tree->hash_move[ply]) {
 
        tree->next_status[ply].phase = GENERATE_ALL_MOVES;
 
        tree->curmv[ply] = tree->hash_move[ply];
 
        if (ValidMove(tree, ply, wtm, tree->curmv[ply]))
 
          return HASH_MOVE;
 
#if defined(DEBUG)
 
        else
 
          Print(128, "bad move from hash table, ply=%d\n", ply);
 
#endif
 
      }
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Now generate all legal moves by using the special       *
 
 *  GenerateCheckEvasions() procedure.  Then sort the moves *
 
 *  based on the expected gain or loss.  this is deferred   *
 
 *  until now to see if the hash move is good enough to     *
 
 *  produce a cutoff and avoid this effort.                 *
 
 *                                                          *
 
 *  Once we confirm that the move does not lose any         *
 
 *  material, we sort these non-losing moves into MVV/LVA   *
 
 *  order which appears to be a slightly faster move        *
 
 *  ordering idea.  Unsafe evasion moves are sorted using   *
 
 *  the original Swap() score to keep them last in the move *
 
 *  list.  Note that this move list contains both captures  *
 
 *  and non-captures.  We try the safe captures first due   *
 
 *  to the way the sort score is computed.                  *
 
 *                                                          *
 
 ************************************************************
 
 */
 
    case GENERATE_ALL_MOVES:
 
      tree->last[ply] =
 
          GenerateCheckEvasions(tree, ply, wtm, tree->last[ply - 1]);
 
      tree->next_status[ply].phase = REMAINING_MOVES;
 
      for (movep = tree->last[ply - 1], sortv = tree->sort_value;
 
          movep < tree->last[ply]; movep++, sortv++)
 
        if (tree->hash_move[ply] && *movep == tree->hash_move[ply]) {
 
          *sortv = -999999;
 
          *movep = 0;
 
        } else {
 
          if (pcval[Piece(*movep)] <= pcval[Captured(*movep)])
 
            *sortv = 128 * pcval[Captured(*movep)] - pcval[Piece(*movep)];
 
          else {
 
            *sortv = Swap(tree, *movep, wtm);
 
            if (*sortv >= 0)
 
              *sortv = 128 * pcval[Captured(*movep)] - pcval[Piece(*movep)];
 
          }
 
        }
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  This is a simple insertion sort algorithm.  It seems be *
 
 *  be no faster than a normal bubble sort, but using this  *
 
 *  eliminated a lot of explaining about "why?". :)         *
 
 *                                                          *
 
 ************************************************************
 
 */
 
      if (tree->last[ply] > tree->last[ply - 1] + 1) {
 
        int temp1, temp2, *tmovep, *tsortv, *end;
 
 
 
        sortv = tree->sort_value + 1;
 
        end = tree->last[ply];
 
        for (movep = tree->last[ply - 1] + 1; movep < end; movep++, sortv++) {
 
          temp1 = *movep;
 
          temp2 = *sortv;
 
          tmovep = movep - 1;
 
          tsortv = sortv - 1;
 
          while (tmovep >= tree->last[ply - 1] && *tsortv < temp2) {
 
            *(tsortv + 1) = *tsortv;
 
            *(tmovep + 1) = *tmovep;
 
            tmovep--;
 
            tsortv--;
 
          }
 
          *(tmovep + 1) = temp1;
 
          *(tsortv + 1) = temp2;
 
        }
 
      }
 
      tree->next_status[ply].last = tree->last[ply - 1];
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Now try the moves in sorted order.                      *
 
 *                                                          *
 
 ************************************************************
 
 */
 
    case REMAINING_MOVES:
 
      for (; tree->next_status[ply].last < tree->last[ply];
 
          tree->next_status[ply].last++)
 
        if (*tree->next_status[ply].last) {
 
          tree->curmv[ply] = *tree->next_status[ply].last++;
 
          return REMAINING_MOVES;
 
        }
 
      return NONE;
 
    default:
 
      printf("oops!  next_status.phase is bad! [evasion %d]\n",  
          tree->next_status[ply].phase);
 
  }
 
  return NONE;
 
}
 
 
 
/* last modified 05/15/14 */
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   NextMove() is used to select the next move from the current move list.    *
 
 *                                                                             *
 
 *   The "excluded move" code below simply collects any moves that were        *
 
 *   searched without being generated (hash move and up to 4 killers).  We     *
 
 *   save them in the NEXT structure and make sure to exclude them when        *
 
 *   searching after a move generation to avoid the duplicated effort.         *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
int NextMove(TREE * RESTRICT tree, int ply, int wtm) {
 
  int *movep, *sortv;
 
 
 
  switch (tree->next_status[ply].phase) {
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  First, try the transposition table move (which will be  *
 
 *  the principal variation move as we first move down the  *
 
 *  tree).                                                  *
 
 *                                                          *
 
 ************************************************************
 
 */
 
    case HASH_MOVE:
 
      tree->next_status[ply].num_excluded = 0;
 
      tree->next_status[ply].phase = GENERATE_CAPTURE_MOVES;
 
      if (tree->hash_move[ply]) {
 
        tree->curmv[ply] = tree->hash_move[ply];
 
        tree->next_status[ply].excluded_moves[tree->next_status[ply].
 
            num_excluded++]
 
            = tree->curmv[ply];
 
        if (ValidMove(tree, ply, wtm, tree->curmv[ply]))
 
          return HASH_MOVE;
 
#if defined(DEBUG)
 
        else
 
          Print(128, "bad move from hash table, ply=%d\n", ply);
 
#endif
 
      }
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Generate captures and sort them based on the simple     *
 
 *  MVV/LVA ordering where we try to capture the most       *
 
 *  valuable victim piece possible, using the least         *
 
 *  valuable attacking piece possible.  Later we will test  *
 
 *  to see if the capture appears to lose material and we   *
 
 *  will defer searching it until later.                    *
 
 *                                                          *
 
 ************************************************************
 
 */
 
    case GENERATE_CAPTURE_MOVES:
 
      tree->next_status[ply].phase = CAPTURE_MOVES;
 
      tree->last[ply] = GenerateCaptures(tree, ply, wtm, tree->last[ply - 1]);
 
      tree->next_status[ply].remaining = 0;
 
      for (movep = tree->last[ply - 1], sortv = tree->sort_value;
 
          movep < tree->last[ply]; movep++, sortv++)
 
        if (*movep == tree->hash_move[ply]) {
 
          *sortv = -999999;
 
          *movep = 0;
 
          tree->next_status[ply].num_excluded = 0;
 
        } else {
 
          *sortv = 128 * pcval[Captured(*movep)] - pcval[Piece(*movep)];
 
          tree->next_status[ply].remaining++;
 
        }
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  This is a simple insertion sort algorithm.  It seems to *
 
 *  be no faster than a normal bubble sort, but using this  *
 
 *  eliminated a lot of explaining about "why?". :)         *
 
 *                                                          *
 
 ************************************************************
 
 */
 
      if (tree->last[ply] > tree->last[ply - 1] + 1) {
 
        int temp1, temp2, *tmovep, *tsortv, *end;
 
 
 
        sortv = tree->sort_value + 1;
 
        end = tree->last[ply];
 
        for (movep = tree->last[ply - 1] + 1; movep < end; movep++, sortv++) {
 
          temp1 = *movep;
 
          temp2 = *sortv;
 
          tmovep = movep - 1;
 
          tsortv = sortv - 1;
 
          while (tmovep >= tree->last[ply - 1] && *tsortv < temp2) {
 
            *(tsortv + 1) = *tsortv;
 
            *(tmovep + 1) = *tmovep;
 
            tmovep--;
 
            tsortv--;
 
          }
 
          *(tmovep + 1) = temp1;
 
          *(tsortv + 1) = temp2;
 
        }
 
      }
 
      tree->next_status[ply].last = tree->last[ply - 1];
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Try the captures moves, which are in order based on     *
 
 *  MVV/LVA ordering.  If a larger-valued piece captures a  *
 
 *  lesser-valued piece, and Swap() says it loses material, *
 
 *  this capture will be deferred until later.              *
 
 *                                                          *
 
 ************************************************************
 
 */
 
    case CAPTURE_MOVES:
 
      while (tree->next_status[ply].remaining) {
 
        tree->curmv[ply] = *(tree->next_status[ply].last++);
 
        if (!--tree->next_status[ply].remaining)
 
          tree->next_status[ply].phase = KILLER_MOVE_1;
 
        if (pcval[Piece(tree->curmv[ply])] > pcval[Captured(tree->curmv[ply])]
 
            && Swap(tree, tree->curmv[ply], wtm) < 0)
 
          continue;
 
        *(tree->next_status[ply].last - 1) = 0;
 
        return CAPTURE_MOVES;
 
      }
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Now, try the killer moves.  This phase tries the two    *
 
 *  killers for the current ply without generating moves,   *
 
 *  which saves time if a cutoff occurs.  After those two   *
 
 *  killers are searched, we try the killers from two plies *
 
 *  back since they have greater depth and might produce a  *
 
 *  cutoff if the current two do not.                       *
 
 *                                                          *
 
 ************************************************************
 
 */
 
    case KILLER_MOVE_1:
 
      if (!Exclude(tree, ply, tree->killers[ply].move1) &&
 
          ValidMove(tree, ply, wtm, tree->killers[ply].move1)) {
 
        tree->curmv[ply] = tree->killers[ply].move1;
 
        tree->next_status[ply].excluded_moves[tree->next_status[ply].
 
            num_excluded++]
 
            = tree->curmv[ply];
 
        tree->next_status[ply].phase = KILLER_MOVE_2;
 
        return KILLER_MOVE_1;
 
      }
 
    case KILLER_MOVE_2:
 
      if (!Exclude(tree, ply, tree->killers[ply].move2) &&
 
          ValidMove(tree, ply, wtm, tree->killers[ply].move2)) {
 
        tree->curmv[ply] = tree->killers[ply].move2;
 
        tree->next_status[ply].excluded_moves[tree->next_status[ply].
 
            num_excluded++]
 
            = tree->curmv[ply];
 
        if (ply < 3) {
 
          tree->next_status[ply].phase = GENERATE_ALL_MOVES;
 
        } else
 
          tree->next_status[ply].phase = KILLER_MOVE_3;
 
        return KILLER_MOVE_2;
 
      }
 
    case KILLER_MOVE_3:
 
      if (!Exclude(tree, ply, tree->killers[ply - 2].move1) &&
 
          ValidMove(tree, ply, wtm, tree->killers[ply - 2].move1)) {
 
        tree->curmv[ply] = tree->killers[ply - 2].move1;
 
        tree->next_status[ply].excluded_moves[tree->next_status[ply].
 
            num_excluded++]
 
            = tree->curmv[ply];
 
        tree->next_status[ply].phase = KILLER_MOVE_4;
 
        return KILLER_MOVE_3;
 
      }
 
    case KILLER_MOVE_4:
 
      if (!Exclude(tree, ply, tree->killers[ply - 2].move2) &&
 
          ValidMove(tree, ply, wtm, tree->killers[ply - 2].move2)) {
 
        tree->curmv[ply] = tree->killers[ply - 2].move2;
 
        tree->next_status[ply].excluded_moves[tree->next_status[ply].
 
            num_excluded++]
 
            = tree->curmv[ply];
 
        tree->next_status[ply].phase = GENERATE_ALL_MOVES;
 
        return KILLER_MOVE_4;
 
      }
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Now, generate all non-capturing moves, which get added  *
 
 *  to the move list behind any captures we did not search. *
 
 *                                                          *
 
 ************************************************************
 
 */
 
    case GENERATE_ALL_MOVES:
 
      tree->last[ply] = GenerateNoncaptures(tree, ply, wtm, tree->last[ply]);
 
      tree->next_status[ply].phase = REMAINING_MOVES;
 
      tree->next_status[ply].last = tree->last[ply - 1];
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Then we try the rest of the set of moves, but we use    *
 
 *  Exclude() function to skip any moves we have already    *
 
 *  searched (hash or killers).                             *
 
 *                                                          *
 
 ************************************************************
 
 */
 
    case REMAINING_MOVES:
 
      for (; tree->next_status[ply].last < tree->last[ply];
 
          tree->next_status[ply].last++)
 
        if (*tree->next_status[ply].last) {
 
          if (!Exclude(tree, ply, *tree->next_status[ply].last)) {
 
            tree->curmv[ply] = *tree->next_status[ply].last++;
 
            return REMAINING_MOVES;
 
          }
 
        }
 
      return NONE;
 
    default:
 
      Print(4095, "oops!  next_status.phase is bad! [normal %d]\n",
 
          tree->next_status[ply].phase);
 
  }
 
  return NONE;
 
}
 
 
 
/* last modified 05/15/14 */
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   NextRootMove() is used to select the next move from the root move list.   *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
int NextRootMove(TREE * RESTRICT tree, TREE * RESTRICT mytree, int wtm) {
 
  int which, i;
 
  uint64_t total_nodes;
 
 
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  First, we check to see if we only have one legal move.  *
 
 *  If so, and we are not pondering, we stop after a short  *
 
 *  search, saving time, but making sure we have something  *
 
 *  to ponder.                                              *
 
 *                                                          *
 
 ************************************************************
 
 */
 
  if (!annotate_mode && !pondering && !booking && n_root_moves == 1 &&
 
      iteration_depth > 4) {
 
    abort_search = 1;
 
    return NONE;
 
  }
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  For the moves at the root of the tree, the list has     *
 
 *  already been generated and sorted.                      *
 
 *                                                          *
 
 *  We simply have to find the first move that has a zero   *
 
 *  "already searched" flag and choose that one.  We do set *
 
 *  the "already searched" flag for this move before we     *
 
 *  return so that it won't be searched again in another    *
 
 *  thread.                                                 *
 
 *                                                          *
 
 ************************************************************
 
 */
 
  for (which = 0; which < n_root_moves; which++)
 
    if (!(root_moves[which].status & 8)) {
 
      if (search_move) {
 
        if (root_moves[which].move != search_move) {
 
          root_moves[which].status |= 8;
 
          continue;
 
        }
 
      }
 
      tree->curmv[1] = root_moves[which].move;
 
      root_moves[which].status |= 8;
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  We have found a move to search.  If appropriate, we     *
 
 *  display this move, along with the time and information  *
 
 *  such as which move this is in the list and how many     *
 
 *  are left to search before this iteration is done, and   *
 
 *  a "status" character that shows the state of the        *
 
 *  current search ("?" means we are pondering, waiting on  *
 
 *  a move to be entered, "*" means we are searching and    *
 
 *  our clock is running).  We also display the NPS for     *
 
 *  the search, simply for information about how fast the   *
 
 *  machine is running.                                     *
 
 *                                                          *
 
 ************************************************************
 
 */
 
      if (tree->nodes_searched > noise_level && display_options & 32) {
 
        Lock(lock_io);
 
        sprintf_s(mytree->remaining_moves_text, sizeof (mytree->remaining_moves_text), "%d/%d", which + 1, // Pierre-Marie Baty -- use safe version
 
            n_root_moves);
 
        end_time = ReadClock();
 
        if (pondering)
 
          printf("         %2i   %s%7s?  ", iteration_depth
,  
              Display2Times(end_time - start_time),
 
              mytree->remaining_moves_text);
 
        else
 
          printf("         %2i   %s%7s*  ", iteration_depth
,  
              Display2Times(end_time - start_time),
 
              mytree->remaining_moves_text);
 
        if (display_options & 32 && display_options & 64)
 
        if (display_options & 32 && display_options & 64 && Flip(wtm))
 
        strcpy_s(mytree->root_move_text, sizeof (mytree->root_move_text), OutputMove(tree, tree->curmv[1], 1, // Pierre-Marie Baty -- use safe version
 
                wtm));
 
        total_nodes = block[0]->nodes_searched;
 
        for (i = 1; i < MAX_BLOCKS; i++)
 
          if (block[i] && block[i]->used)
 
            total_nodes += block[i]->nodes_searched;
 
        nodes_per_second = (unsigned int) (total_nodes * 100 / Max(end_time - start_time, 1)); // Pierre-Marie Baty -- added type cast
 
        i 
= strlen(mytree
->root_move_text
); 
        i = (i < 8) ? i : 8;
 
        strncat_s(mytree->root_move_text, sizeof (mytree->root_move_text), "          ", 8 - i); // Pierre-Marie Baty -- use safe version
 
        printf("%s", mytree
->root_move_text
);  
        printf("(%snps)             \r", DisplayKMB
(nodes_per_second
));  
        Unlock(lock_io);
 
      }
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Bit of a tricky exit.  If the move is not flagged as    *
 
 *  "OK to search in parallel or reduce" then we return     *
 
 *  "HASH_MOVE" which will prevent Search() from reducing   *
 
 *  the move (LMR).  Otherwise we return the more common    *
 
 *  "REMAINING_MOVES" value which allows LMR to be used on  *
 
 *  those root moves.                                       *
 
 *                                                          *
 
 ************************************************************
 
 */
 
      if ((root_moves[which].status & 4) == 0)
 
        return HASH_MOVE;
 
      else
 
        return REMAINING_MOVES;
 
    }
 
  return NONE;
 
}
 
 
 
/* last modified 05/15/14 */
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   NextRootMoveParallel() is used to determine if the next root move can be  *
 
 *   searched in parallel.  If it appears to Iterate() that one of the moves   *
 
 *   following the first move might become the best move, the 'no parallel'    *
 
 *   flag is set to speed up finding the new best move.  This flag is set if   *
 
 *   this root move has an "age" value > 0 which indicates this move was the   *
 
 *   "best move" within the previous 3 search depths.  We want to search such  *
 
 *   moves as quickly as possible, prior to starting a parallel search at the  *
 
 *   root, in case this move once again becomes the best move and provides a   *
 
 *   better alpha bound.                                                       *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
int NextRootMoveParallel(void) {
 
  int which;
 
 
 
/*
 
 ************************************************************
 
 *                                                          *
 
 *  Here we simply check the root_move status flag that is  *
 
 *  set in Iterate() after each iteration is completed.  A  *
 
 *  value of "1" indicates this move has to be searched by  *
 
 *  all processors, splitting must wait until after all     *
 
 *  such moves have been searched individually.             *
 
 *                                                          *
 
 ************************************************************
 
 */
 
  for (which = 0; which < n_root_moves; which++)
 
    if (!(root_moves[which].status & 8))
 
      break;
 
  if (which < n_root_moves && root_moves[which].status & 4)
 
    return 1;
 
  return 0;
 
}
 
 
 
/* last modified 05/15/14 */
 
/*
 
 *******************************************************************************
 
 *                                                                             *
 
 *   Exclude() searches the list of moves searched prior to generating a move  *
 
 *   list to exclude those that were searched via a hash table best move or    *
 
 *   through the killer moves for the current ply and two plies back.          *
 
 *                                                                             *
 
 *   The variable next_status[].num_excluded is the total number of non-       *
 
 *   generated moves we searched.  next_status[].remaining is initially set to *
 
 *   num_excluded, but each time an excluded move is found, the counter is     *
 
 *   decremented.  Once all excluded moves have been found, we avoid running   *
 
 *   through the list of excluded moves on each call and simply return.        *
 
 *                                                                             *
 
 *******************************************************************************
 
 */
 
int Exclude(TREE * RESTRICT tree, int ply, int move) {
 
  int i;
 
 
 
  if (tree->next_status[ply].num_excluded)
 
    for (i = 0; i < tree->next_status[ply].num_excluded; i++)
 
      if (move == tree->next_status[ply].excluded_moves[i]) {
 
        tree->next_status[ply].remaining--;
 
        return 1;
 
      }
 
  return 0;
 
}