コード例 #1
0
ファイル: next.cpp プロジェクト: raimarHD/lcec
void InitCaptures(POS *p, MOVES *m) {

  m->phase = 0;
  m->p = p;
  m->last = GenerateCaptures(m->p, m->move);
  ScoreCaptures(m);
  m->next = m->move;
}
コード例 #2
0
/*
********************************************************************************
*                                                                              *
*   Ponder() is the driver for "pondering" (thinking on the opponent's time.)  *
*   its operation is simple:  find a predicted move by (a) taking the second   *
*   move from the principal variation, or (b) call lookup to see if it finds   *
*   a suggested move from the transposition table.  then, make this move and   *
*   do a search from the resulting position.  while pondering, one of three    *
*   things can happen:  (1) a move is entered, and it matches the predicted    *
*   move.  we then switch from pondering to thinking and search as normal;     *
*   (2) a move is entered, but it does not match the predicted move.  we then  *
*   abort the search, unmake the pondered move, and then restart with the move *
*   entered.  (3) a command is entered.  if it is a simple command, it can be  *
*   done without aborting the search or losing time.  if not, we abort the     *
*   search, execute the command, and then attempt to restart pondering if the  *
*   command didn't make that impossible.                                       *
*                                                                              *
********************************************************************************
*/
int Ponder(int wtm)
{
  int dummy=0, i, *n_ponder_moves, *mv;
/*
 ----------------------------------------------------------
|                                                          |
|   first, let's check to see if pondering is allowed, or  |
|   if we should avoid pondering on this move since it is  |
|   the first move of a game, or if the game is over, or   |
|   "force" mode is active, or there is input in the queue |
|   that needs to be read and processed.                   |
|                                                          |
 ----------------------------------------------------------
*/
  if (!ponder || force || over || CheckInput()) return(0);
/*
 ----------------------------------------------------------
|                                                          |
|   if we don't have a predicted move to ponder, try two   |
|   sources:  (1) look up the current position in the      |
|   transposition table and see if it has a suggested best |
|   move;  (2) do a short tree search to calculate a move  |
|   that we should ponder.                                 |
|                                                          |
 ----------------------------------------------------------
*/
  strcpy(hint,"none");
  if (!ponder_move) {
    (void) LookUp(0,0,wtm,&dummy,&dummy);
    if (hash_move[0]) ponder_move=hash_move[0];
  }
  if (!ponder_move) {
    TimeSet(puzzle);
    if (time_limit < 3) return(0);
    puzzling=1;
    position[1]=position[0];
    printf("              puzzling over a move to ponder.\n");
    last_pv.path_length=0;
    last_pv.path_iteration_depth=0;
    for (i=0;i<MAXPLY;i++) {
      killer_move1[i]=0;
      killer_move2[i]=0;
      killer_count1[i]=0;
      killer_count2[i]=0;
    }
    (void) Iterate(wtm,puzzle,0);
    for (i=0;i<MAXPLY;i++) {
      killer_move1[i]=0;
      killer_move2[i]=0;
      killer_count1[i]=0;
      killer_count2[i]=0;
    }
    puzzling=0;
    if (pv[0].path_length) ponder_move=pv[0].path[1];
    if (!ponder_move) return(0);
    for (i=1;i<(int) pv[0].path_length-1;i++) last_pv.path[i]=pv[0].path[i+1];
    last_pv.path_length=pv[0].path_length-1;
    last_pv.path_iteration_depth=0;
    if (!ValidMove(1,wtm,ponder_move)) {
      ponder_move=0;
      return(0);
    }
  }
/*
 ----------------------------------------------------------
|                                                          |
|   display the move we are going to "ponder".             |
|                                                          |
 ----------------------------------------------------------
*/
  if (wtm)
    printf("White(%d): %s [pondering]\n",
          move_number,OutputMove(&ponder_move,0,wtm));
  else
    printf("Black(%d): %s [pondering]\n",
          move_number,OutputMove(&ponder_move,0,wtm));
  sprintf(hint,"%s",OutputMove(&ponder_move,0,wtm));
  if (post) printf("Hint: %s\n",hint);
/*
 ----------------------------------------------------------
|                                                          |
|   set the ponder move list and eliminate illegal moves.  |
|                                                          |
 ----------------------------------------------------------
*/
  n_ponder_moves=GenerateCaptures(0, wtm, ponder_moves);
  num_ponder_moves=GenerateNonCaptures(0, wtm, n_ponder_moves)-ponder_moves;
  for (mv=ponder_moves;mv<ponder_moves+num_ponder_moves;mv++) {
    MakeMove(0, *mv, wtm);
    if (Check(wtm)) {
      UnMakeMove(0, *mv, wtm);
      *mv=0;
      }
    else UnMakeMove(0, *mv, wtm);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   now, perform an iterated search, but with the special  |
|   "pondering" flag set which changes the time controls   |
|   since there is no need to stop searching until the     |
|   opponent makes a move.                                 |
|                                                          |
 ----------------------------------------------------------
*/
  MakeMove(0,ponder_move,wtm);
  if (Rule50Moves(1)==90 || Rule50Moves(1)==91) ClearHashTables();
  last_opponent_move=ponder_move;
  if (ChangeSide(wtm))
    *rephead_w++=HashKey;
  else
    *rephead_b++=HashKey;
  if (RepetitionDraw(wtm)) printf("game is a draw by repetition\n");
  if (whisper) strcpy(whisper_text,"n/a");
  thinking=0;
  pondering=1;
  (void) Iterate(ChangeSide(wtm),think,0);
  pondering=0;
  thinking=0;
  if (ChangeSide(wtm))
    rephead_w--;
  else
    rephead_b--;
  last_opponent_move=0;
  UnMakeMove(0,ponder_move,wtm);
/*
 ----------------------------------------------------------
|                                                          |
|   search completed. the possible return values are:      |
|                                                          |
|   (0) no pondering was done, period.                     |
|                                                          |
|   (1) pondering was done, opponent made the predicted    |
|       move, and we searched until time ran out in a      |
|       normal manner.                                     |
|                                                          |
|   (2) pondering was done, but the ponder search          |
|       terminated due to either finding a mate, or the    |
|       maximum search depth was reached.  the result of   |
|       this ponder search are valid, but only if the      |
|       opponent makes the correct (predicted) move.       |
|                                                          |
|   (3) pondering was done, but the opponent either made   |
|       a different move, or entered a command that has to |
|       interrupt the pondering search before the command  |
|       (or move) can be processed.  this forces Main() to |
|       avoid reading in a move/command since one has been |
|       read into the command buffer already.              |
|                                                          |
 ----------------------------------------------------------
*/
  if (made_predicted_move) return(1);
  if (abort_search) return(3);
  return(2);
}
コード例 #3
0
/*
********************************************************************************
*                                                                              *
*   Ponder() is the driver for "pondering" (thinking on the opponent's time.)  *
*   its operation is simple:  find a predicted move by (a) taking the second   *
*   move from the principal variation, or (b) call lookup to see if it finds   *
*   a suggested move from the transposition table.  then, make this move and   *
*   do a search from the resulting position.  while pondering, one of three    *
*   things can happen:  (1) a move is entered, and it matches the predicted    *
*   move.  we then switch from pondering to thinking and search as normal;     *
*   (2) a move is entered, but it does not match the predicted move.  we then  *
*   abort the search, unmake the pondered move, and then restart with the move *
*   entered.  (3) a command is entered.  if it is a simple command, it can be  *
*   done without aborting the search or losing time.  if not, we abort the     *
*   search, execute the command, and then attempt to restart pondering if the  *
*   command didn't make that impossible.                                       *
*                                                                              *
********************************************************************************
*/
int Ponder(int wtm)
{
  int dummy=0, i, *n_ponder_moves;

/*
 ----------------------------------------------------------
|                                                          |
|   if we don't have a predicted move to ponder, try two   |
|   sources:  (1) look up the current position in the      |
|   transposition table and see if it has a suggested best |
|   move;  (2) do a short tree search to calculate a move  |
|   that we should ponder.                                 |
|                                                          |
 ----------------------------------------------------------
*/
  ponder_completed=0;
  if (!ponder_move) {
    (void) LookUp(0,0,wtm,&dummy,dummy);
    if (hash_move[0]) ponder_move=hash_move[0];
  }
  if (!ponder_move) {
    TimeSet(puzzle);
    if (time_limit < 3) return(0);
    puzzling=1;
    position[1]=position[0];
    Print(2,"              puzzling over a move to ponder.\n");
    last_pv.path_length=0;
    last_pv.path_iteration_depth=0;
    for (i=0;i<MAXPLY;i++) {
      killer_move1[i]=0;
      killer_move2[i]=0;
      killer_count1[i]=0;
      killer_count2[i]=0;
    }
    (void) Iterate(wtm,puzzle);
    for (i=0;i<MAXPLY;i++) {
      killer_move1[i]=0;
      killer_move2[i]=0;
      killer_count1[i]=0;
      killer_count2[i]=0;
    }
    puzzling=0;
    if (pv[0].path_length) ponder_move=pv[0].path[1];
    if (!ponder_move) return(0);
    for (i=1;i<(int) pv[0].path_length-1;i++) last_pv.path[i]=pv[0].path[i+1];
    last_pv.path_length=pv[0].path_length-1;
    last_pv.path_iteration_depth=0;
    if (!ValidMove(1,wtm,ponder_move)) {
      printf("puzzle returned an illegal move!\n");
      DisplayChessMove("move= ",ponder_move);
      ponder_move=0;
      return(0);
    }
  }
  if (!ponder_move) {
    strcpy(hint,"none");
    return(0);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   display the move we are going to "ponder".             |
|                                                          |
 ----------------------------------------------------------
*/
  if (wtm)
    Print(2,"White(%d): %s [pondering]\n",
          move_number,OutputMove(&ponder_move,0,wtm));
  else
    Print(2,"Black(%d): %s [pondering]\n",
          move_number,OutputMove(&ponder_move,0,wtm));
  sprintf(hint,"%s",OutputMove(&ponder_move,0,wtm));
  n_ponder_moves=GenerateCaptures(0, wtm, ponder_moves);
  num_ponder_moves=GenerateNonCaptures(0, wtm, n_ponder_moves)-ponder_moves;
/*
 ----------------------------------------------------------
|                                                          |
|   now, perform an iterated search, but with the special  |
|   "pondering" flag set which changes the time controls   |
|   since there is no need to stop searching until the     |
|   opponent makes a move.                                 |
|                                                          |
 ----------------------------------------------------------
*/
  MakeMove(0,ponder_move,wtm);
  if (Rule50Moves(1)==90 || Rule50Moves(1)==91) ClearHashTables();
  last_opponent_move=ponder_move;
  if (ChangeSide(wtm))
    *rephead_w++=HashKey;
  else
    *rephead_b++=HashKey;
  if (RepetitionDraw(wtm)) Print(0,"game is a draw by repetition\n");
  if (whisper) strcpy(whisper_text,"n/a");
  pondering=1;
  (void) Iterate(ChangeSide(wtm),think);
  pondering=0;
  if (!abort_search) ponder_completed=1;
  if (ChangeSide(wtm))
    rephead_w--;
  else
    rephead_b--;
  last_opponent_move=0;
  UnMakeMove(0,ponder_move,wtm);
/*
 ----------------------------------------------------------
|                                                          |
|   search completed.  there are two possible reasons for  |
|   us to get here.  (1) the opponent made the predicted   |
|   move and we have used enough time on the search, or;   |
|   the operator typed in a command (or not-predicted      |
|   move) that requires the search to abort and restart.   |
|                                                          |
 ----------------------------------------------------------
*/
  if (made_predicted_move) return(1);
  return(0);
}
コード例 #4
0
ファイル: ponder.c プロジェクト: B4dT0bi/JniChessEngines
/*
 *******************************************************************************
 *                                                                             *
 *   Ponder() is the driver for "pondering" (thinking on the opponent's time.) *
 *   its operation is simple:  Find a predicted move by (a) taking the second  *
 *   move from the principal variation, or (b) call lookup to see if it finds  *
 *   a suggested move from the transposition table.  Then, make this move and  *
 *   do a search from the resulting position.  While pondering, one of three   *
 *   things can happen:  (1) A move is entered, and it matches the predicted   *
 *   move.  We then switch from pondering to thinking and search as normal;    *
 *   (2) A move is entered, but it does not match the predicted move.  We then *
 *   abort the search, unmake the pondered move, and then restart with the     *
 *   move entered.  (3) A command is entered.  If it is a simple command, it   *
 *   can be done without aborting the search or losing time.  If not, we abort *
 *   the search, execute the command, and then attempt to restart pondering if *
 *   the command didn't make that impossible.                                  *
 *                                                                             *
 *******************************************************************************
 */
int Ponder(int wtm) {
  TREE *const tree = block[0];
  int dalpha = -999999, dbeta = 999999, i;
  unsigned *n_ponder_moves, *mv;
  int save_move_number, tlom, value;

/*
 ************************************************************
 *                                                          *
 *  First, let's check to see if pondering is allowed, or   *
 *  if we should avoid pondering on this move since it is   *
 *  the first move of a game, or if the game is over, or    *
 *  "force" mode is active, or there is input in the queue  *
 *  that needs to be read and processed.                    *
 *                                                          *
 ************************************************************
 */
  if (!ponder || force || over || CheckInput())
    return 0;
  save_move_number = move_number;
/*
 ************************************************************
 *                                                          *
 *  Check the ponder move for legality.  If it is not a     *
 *  legal move, we have to take action to find something to *
 *  ponder.                                                 *
 *                                                          *
 ************************************************************
 */
  strcpy(ponder_text, "none");
  if (ponder_move) {
    if (!VerifyMove(tree, 1, wtm, ponder_move)) {
      ponder_move = 0;
      Print(4095, "ERROR.  ponder_move is illegal (1).\n");
      Print(4095, "ERROR.  PV pathl=%d\n", last_pv.pathl);
      Print(4095, "ERROR.  move=%d  %x\n", ponder_move, ponder_move);
    }
  }
/*
 ************************************************************
 *                                                          *
 *  First attempt, do a hash probe.  However, since a hash  *
 *  collision is remotely possible, we still need to verify *
 *  that the transposition/refutation best move is actually *
 *  legal.                                                  *
 *                                                          *
 ************************************************************
 */
  if (!ponder_move) {
    HashProbe(tree, 0, 0, wtm, dalpha, dbeta, &value);
    if (tree->hash_move[0])
      ponder_move = tree->hash_move[0];
    if (ponder_move) {
      if (!VerifyMove(tree, 1, wtm, ponder_move)) {
        Print(4095, "ERROR.  ponder_move is illegal (2).\n");
        Print(4095, "ERROR.  move=%d  %x\n", ponder_move, ponder_move);
        ponder_move = 0;
      }
    }
  }
/*
 ************************************************************
 *                                                          *
 *  Second attempt.  If that didn't work, then we try what  *
 *  I call a "puzzling" search.  Which is simply a shorter  *
 *  time-limit search for the other side, to find something *
 *  to ponder.                                              *
 *                                                          *
 ************************************************************
 */
  if (!ponder_move) {
    TimeSet(puzzle);
    if (time_limit < 20)
      return 0;
    puzzling = 1;
    tree->status[1] = tree->status[0];
    Print(32, "              puzzling over a move to ponder.\n");
    last_pv.pathl = 0;
    last_pv.pathd = 0;
    for (i = 0; i < MAXPLY; i++) {
      tree->killers[i].move1 = 0;
      tree->killers[i].move2 = 0;
    }
    Iterate(wtm, puzzle, 0);
    for (i = 0; i < MAXPLY; i++) {
      tree->killers[i].move1 = 0;
      tree->killers[i].move2 = 0;
    }
    puzzling = 0;
    if (tree->pv[0].pathl)
      ponder_move = tree->pv[0].path[1];
    if (!ponder_move)
      return 0;
    for (i = 1; i < (int) tree->pv[0].pathl; i++)
      last_pv.path[i] = tree->pv[0].path[i + 1];
    last_pv.pathl = tree->pv[0].pathl - 1;
    last_pv.pathd = 0;
    if (!VerifyMove(tree, 1, wtm, ponder_move)) {
      ponder_move = 0;
      Print(4095, "ERROR.  ponder_move is illegal (3).\n");
      Print(4095, "ERROR.  PV pathl=%d\n", last_pv.pathl);
      return 0;
    }
  }
/*
 ************************************************************
 *                                                          *
 *  Display the move we are going to "ponder".              *
 *                                                          *
 ************************************************************
 */
  if (wtm)
    Print(32, "White(%d): %s [pondering]\n", move_number, OutputMove(tree, 0,
            wtm, ponder_move));
  else
    Print(32, "Black(%d): %s [pondering]\n", move_number, OutputMove(tree, 0,
            wtm, ponder_move));
  sprintf(ponder_text, "%s", OutputMove(tree, 0, wtm, ponder_move));
  if (post)
    printf("Hint: %s\n", ponder_text);
/*
 ************************************************************
 *                                                          *
 *  Set the ponder move list and eliminate illegal moves.   *
 *  This list is used to test the move entered while we are *
 *  pondering, since we need a move list for the input      *
 *  screening process.                                      *
 *                                                          *
 ************************************************************
 */
  n_ponder_moves = GenerateCaptures(tree, 0, wtm, ponder_moves);
  num_ponder_moves =
      GenerateNoncaptures(tree, 0, wtm, n_ponder_moves) - ponder_moves;
  for (mv = ponder_moves; mv < ponder_moves + num_ponder_moves; mv++) {
    MakeMove(tree, 0, wtm, *mv);
    if (Check(wtm)) {
      UnmakeMove(tree, 0, wtm, *mv);
      *mv = 0;
    } else
      UnmakeMove(tree, 0, wtm, *mv);
  }
/*
 ************************************************************
 *                                                          *
 *  Now, perform an iterated search, but with the special   *
 *  "pondering" flag set which changes the time controls    *
 *  since there is no need to stop searching until the      *
 *  opponent makes a move.                                  *
 *                                                          *
 ************************************************************
 */
  MakeMove(tree, 0, wtm, ponder_move);
  tree->curmv[0] = ponder_move;
  tree->rep_list[++rep_index] = HashKey;
  tlom = last_opponent_move;
  last_opponent_move = ponder_move;
  if (kibitz)
    strcpy(kibitz_text, "n/a");
  thinking = 0;
  pondering = 1;
  if (!wtm)
    move_number++;
  ponder_value = Iterate(Flip(wtm), think, 0);
  rep_index--;
  move_number = save_move_number;
  pondering = 0;
  thinking = 0;
  last_opponent_move = tlom;
  UnmakeMove(tree, 0, wtm, ponder_move);
/*
 ************************************************************
 *                                                          *
 *  Search completed. the possible return values are:       *
 *                                                          *
 *  (0) No pondering was done, period.                      *
 *                                                          *
 *  (1) Pondering was done, opponent made the predicted     *
 *      move, and we searched until time ran out in a       *
 *      normal manner.                                      *
 *                                                          *
 *  (2) Pondering was done, but the ponder search           *
 *      terminated due to either finding a mate, or the     *
 *      maximum search depth was reached.  The result of    *
 *      this ponder search are valid, but only if the       *
 *      opponent makes the correct (predicted) move.        *
 *                                                          *
 *  (3) Pondering was done, but the opponent either made a  *
 *      different move, or entered a command that has to    *
 *      interrupt the pondering search before the command   *
 *      (or move) can be processed.  This forces Main() to  *
 *      avoid reading in a move/command since one has been  *
 *      read into the command buffer already.               *
 *                                                          *
 ************************************************************
 */
  if (input_status == 1)
    return 1;
  if (input_status == 2)
    return 3;
  return 2;
}
コード例 #5
0
ファイル: next.cpp プロジェクト: raimarHD/lcec
int NextMove(MOVES *m, int *flag) {

  int move;

  switch (m->phase) {
  case 0: // return transposition table move, if legal
    move = m->trans_move;
    if (move 
    && Legal(m->p, move)) {
      m->phase = 1;
      *flag = MV_HASH;
      return move;
    }

  case 1: // helper phase: generate captures
    m->last = GenerateCaptures(m->p, m->move);
    ScoreCaptures(m);
    m->next = m->move;
    m->badp = m->bad;
    m->phase = 2;

  case 2: // return good captures, save bad ones on the separate list
    while (m->next < m->last) {
      move = SelectBest(m);

      if (move == m->trans_move)
        continue;

      if (BadCapture(m->p, move)) {
        *m->badp++ = move;
        continue;
      }
      *flag = MV_CAPTURE;
      return move;
    }

  case 3:  // first killer move
    move = m->killer1;
    if (move 
    && move != m->trans_move 
    && m->p->pc[Tsq(move)] == NO_PC 
    && Legal(m->p, move)) {
      m->phase = 4;
      *flag = MV_KILLER;
      return move;
    }

  case 4:  // second killer move
    move = m->killer2;
    if (move 
    && move != m->trans_move 
    && m->p->pc[Tsq(move)] == NO_PC 
    && Legal(m->p, move)) {
      m->phase = 5;
      *flag = MV_KILLER;
      return move;
    }

  case 5: // refutation move
    move = m->ref_move;
    if (move && move != m->trans_move 
    &&  m->p->pc[Tsq(move)] == NO_PC 
    &&  move != m->killer1
    &&  move != m->killer2
    && Legal(m->p, move)) {
      m->phase = 6;
      *flag = MV_NORMAL;
      return move;
    }

  case 6:  // helper phase: generate quiet moves
    m->last = GenerateQuiet(m->p, m->move);
    ScoreQuiet(m);
    m->next = m->move;
    m->phase = 7;

  case 7:  // return quiet moves
    while (m->next < m->last) {
      move = SelectBest(m);
      if (move == m->trans_move
      ||  move == m->killer1
      ||  move == m->killer2
      ||  move == m->ref_move)
        continue;
      *flag = MV_NORMAL;
      return move;
    }

    m->next = m->bad;
    m->phase = 8;

  case 8: // return bad captures
    if (m->next < m->badp) {
      *flag = MV_BADCAPT;
      return *m->next++;
    }
  }
  return 0;
}
コード例 #6
0
/*
********************************************************************************
*                                                                              *
*   Quiesce() is the recursive routine used to implement the alpha/beta        *
*   negamax search (similar to minimax but simpler to code.)  Quiesce() is     *
*   called whenever there is no "depth" remaining so that only capture moves   *
*   are searched deeper.                                                       *
*                                                                              *
********************************************************************************
*/
int Quiesce(int alpha, int beta, int wtm, int ply)
{
  register int initial_alpha, value, delta;
  register int *next_move;
  register int *goodmv, *movep, moves=0, *sortv, temp;
/*
 ----------------------------------------------------------
|                                                          |
|   initialize.                                            |
|                                                          |
 ----------------------------------------------------------
*/
  if (ply >= MAXPLY-2) return(beta);
  nodes_searched++;
  next_time_check--;
  last[ply]=last[ply-1];
  initial_alpha=alpha;
/*
 ----------------------------------------------------------
|                                                          |
|   now call Evaluate() to produce the "stand-pat" score   |
|   that will be returned if no capture is acceptable.     |
|   if this score is > alpha, then we also have to save    |
|   the "path" to this node as it is the PV that leads     |
|   to this score.                                         |
|                                                          |
 ----------------------------------------------------------
*/
  value=Evaluate(ply,wtm,alpha,beta);
  if (value > alpha) {
    if (value >= beta) return(value);
    alpha=value;
    pv[ply].path_length=ply-1;
    pv[ply].path_hashed=0;
    pv[ply].path_iteration_depth=iteration_depth;
  }
/*
 ----------------------------------------------------------
|                                                          |
|   generate captures and sort them based on (a) the value |
|   of the captured piece - the value of the capturing     |
|   piece if this is > 0; or, (b) the value returned by    |
|   Swap().  if the value of the captured piece won't      |
|   bring the material score back up to near alpha, that   |
|   capture is discarded as "futile."                      |
|                                                          |
 ----------------------------------------------------------
*/
  last[ply]=GenerateCaptures(ply, wtm, last[ply-1]);
  delta=alpha-500-(wtm?Material:-Material);
  goodmv=last[ply-1];
  sortv=sort_value;
  for (movep=last[ply-1];movep<last[ply];movep++)
    if (p_values[Captured(*movep)+7]+p_values[Promote(*movep)+7] >= delta) {
      if (Captured(*movep) == king) return(beta);
      if (p_values[Piece(*movep)+7] < p_values[Captured(*movep)+7] ||
          (p_values[Piece(*movep)+7] <= p_values[Captured(*movep)+7] &&
           delta<=0)) {
        *goodmv++=*movep;
        *sortv++=p_values[Captured(*movep)+7];
        moves++;
      }
      else {
        temp=Swap(From(*movep),To(*movep),wtm);
        if (temp >= 0) {
          *sortv++=temp;
          *goodmv++=*movep;
          moves++;
        }
      }
    }
/*
 ----------------------------------------------------------
|                                                          |
|   don't disdain the lowly bubble sort here.  the list of |
|   captures is always short, and experiments with other   |
|   algorithms are always slightly slower.                 |
|                                                          |
 ----------------------------------------------------------
*/
  if (moves > 1) {
    register int done;
    register int *end=last[ply-1]+moves-1;
    do {
      done=1;
      sortv=sort_value;
      movep=last[ply-1];
      for (;movep<end;movep++,sortv++)
        if (*sortv < *(sortv+1)) {
          temp=*sortv;
          *sortv=*(sortv+1);
          *(sortv+1)=temp;
          temp=*movep;
          *movep=*(movep+1);
          *(movep+1)=temp;
          done=0;
        }
    } while(!done);
  }
  next_move=last[ply-1];
/*
 ----------------------------------------------------------
|                                                          |
|   now iterate through the move list and search the       |
|   resulting positions.                                   |
|                                                          |
 ----------------------------------------------------------
*/
  while (moves--) {
    current_move[ply]=*(next_move++);
#if !defined(FAST)
    if (ply <= trace_level)
      SearchTrace(ply,0,wtm,alpha,beta,"quiesce",CAPTURE_MOVES);
#endif
    MakeMove(ply,current_move[ply],wtm);
    value=-Quiesce(-beta,-alpha,ChangeSide(wtm),ply+1);
    UnMakeMove(ply,current_move[ply],wtm);
    if (value > alpha) {
      if(value >= beta) return(value);
      alpha=value;
    }
  }
/*
 ----------------------------------------------------------
|                                                          |
|   all moves have been searched.  return the search       |
|   result that was found.  if the result is not the       |
|   original alpha score, then we need to return the PV    |
|   that is associated with this score.                    |
|                                                          |
 ----------------------------------------------------------
*/
  if (alpha != initial_alpha) {
    memcpy(&pv[ply-1].path[ply],&pv[ply].path[ply],
           (pv[ply].path_length-ply+1)*sizeof(int));
    memcpy(&pv[ply-1].path_hashed,&pv[ply].path_hashed,3);
    pv[ply-1].path[ply-1]=current_move[ply-1];
  }
  return(alpha);
}