/*
********************************************************************************
*                                                                              *
*   StorePV() is called by Iterate() to insert the PV moves so they will be    *
*   searched before any other moves.                                           *
*                                                                              *
********************************************************************************
*/
void StorePV(int ply, int wtm)
{
  register BITBOARD temp_hash_key;
  register HASH_ENTRY *htable;
/*
 ----------------------------------------------------------
|                                                          |
|   make sure the move being stored is legal, so that a    |
|   bad move doesn't get into hash table.                  |
|                                                          |
 ----------------------------------------------------------
*/
  if (!ValidMove(ply,wtm,pv[ply].path[ply])) {
    printf("\ninstalling bogus move...ply=%d\n",ply);
    printf("installing %s\n",OutputMove(&pv[ply].path[ply],ply,wtm));
    return;
  }
/*
 ----------------------------------------------------------
|                                                          |
|   first, compute the initial hash address and choose     |
|   which hash table (based on color) to probe.            |
|                                                          |
 ----------------------------------------------------------
*/
  temp_hash_key=HashKey;
  htable=((wtm) ? trans_ref_wb : trans_ref_bb)+(((int) temp_hash_key)&hash_maskb);
  temp_hash_key=temp_hash_key>>16;
/*
 ----------------------------------------------------------
|                                                          |
|   now "fill in the blank" and build a table entry from   |
|   current search information.                            |
|                                                          |
 ----------------------------------------------------------
*/
  htable->word1=Shiftl((BITBOARD) 65536,21);
  htable->word1=Or(htable->word1,Shiftl((BITBOARD) ((transposition_id<<2)+WORTHLESS),59));
  htable->word1=Or(htable->word1,(BITBOARD) pv[ply].path[ply]);
  htable->word2=temp_hash_key;
}
/*
********************************************************************************
*                                                                              *
*   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);
}
Esempio n. 3
0
/*
 *******************************************************************************
 *                                                                             *
 *   Analyze() is used to handle the "analyze" command.  This mode basically   *
 *   puts Crafty into a "permanent pondering" state, where it reads a move     *
 *   from the input stream, and then "ponders" for the opposite side.          *
 *   Whenever a move is entered, Crafty reads this move, updates the game      *
 *   board, and then starts "pondering" for the other side.                    *
 *                                                                             *
 *   The purpose of this mode is to force Crafty to follow along in a game,    *
 *   providing analysis continually for the side on move until a move is       *
 *   entered, advancing the game to the next position.                         *
 *                                                                             *
 *******************************************************************************
 */
void Analyze() {
  int i, move, back_number, readstat = 1;
  TREE *const tree = block[0];

/*
 ************************************************************
 *                                                          *
 *  Initialize.                                             *
 *                                                          *
 ************************************************************
 */
  int save_swindle_mode = swindle_mode;

  swindle_mode = 0;
  ponder_move = 0;
  analyze_mode = 1;
  if (!xboard)
    display_options |= 1 + 2 + 4;
  _printf("Analyze Mode: type \"exit\" to terminate.\n");
/*
 ************************************************************
 *                                                          *
 *  Now loop waiting on input, searching the current        *
 *  position continually until a move comes in.             *
 *                                                          *
 ************************************************************
 */
  do {
    do {
      last_pv.pathd = 0;
      last_pv.pathl = 0;
      input_status = 0;
      pondering = 1;
      tree->status[1] = tree->status[0];
      Iterate(game_wtm, think, 0);
      pondering = 0;
      if (book_move)
        moves_out_of_book = 0;
      if (!xboard) {
        if (game_wtm)
          _printf("analyze.White(%d): ", move_number);
        else
          _printf("analyze.Black(%d): ", move_number);
        fflush(stdout);
      }
/*
 ************************************************************
 *                                                          *
 *  If we get back to here, something has been typed in and *
 *  is in the command buffer normally, unless the search    *
 *  terminated naturally due to finding a mate or reaching  *
 *  the max depth allowable.                                *
 *                                                          *
 ************************************************************
 */
      if (!input_status)
        do {
          readstat = Read(1, buffer);
          if (readstat < 0)
            break;
          nargs = ReadParse(buffer, args, " 	;");
          Print(128, "%s\n", buffer);
          if (strstr(args[0], "timeleft") && !xboard) {
            if (game_wtm)
              _printf("analyze.White(%d): ", move_number);
            else
              _printf("analyze.Black(%d): ", move_number);
            fflush(stdout);
          }
        } while (strstr(args[0], "timeleft"));
      else
        nargs = ReadParse(buffer, args, " 	;");
      if (readstat < 0)
        break;
      move = 0;
      if (!strcmp(args[0], "exit"))
        break;
/*
 ************************************************************
 *                                                          *
 *  First, check for the special analyze command "back n"   *
 *  and handle it if present, otherwise try Option() to see *
 *  if it recognizes the input as a command.                *
 *                                                          *
 ************************************************************
 */
      if (OptionMatch("back", args[0])) {
        if (nargs > 1)
          back_number = atoi(args[1]);
        else
          back_number = 1;
        for (i = 0; i < back_number; i++) {
          game_wtm = Flip(game_wtm);
          if (Flip(game_wtm))
            move_number--;
        }
        if (move_number == 0) {
          move_number = 1;
          game_wtm = 1;
        }
        sprintf(buffer, "reset %d", move_number);
        Option(tree);
        display = tree->position;
      } else if (Option(tree)) {
        display = tree->position;
      }
/*
 ************************************************************
 *                                                          *
 *  If InputMove() can recognize this as a move, make it,   *
 *  swap sides, and return to the top of the loop to call   *
 *  search from this new position.                          *
 *                                                          *
 ************************************************************
 */
      else if ((move = InputMove(tree, buffer, 0, game_wtm, 1, 0))) {
        char *outmove = OutputMove(tree, move, 0, game_wtm);

        if (history_file) {
          fseek(history_file, ((move_number - 1) * 2 + 1 - game_wtm) * 10,
              SEEK_SET);
          fprintf(history_file, "%9s\n", outmove);
        }
        if (game_wtm)
          Print(128, "White(%d): ", move_number);
        else
          Print(128, "Black(%d): ", move_number);
        Print(128, "%s\n", outmove);
        if (speech) {
          char announce[64];

          //strcpy(announce, SPEAK);
          //strcat(announce, outmove);
          //system(announce);

          SPEAK(outmove);
        }
        MakeMoveRoot(tree, move, game_wtm);
        display = tree->position;
        last_mate_score = 0;
        if (log_file)
          DisplayChessBoardFile(log_file, tree->position);
      }
/*
 ************************************************************
 *                                                          *
 *  If Option() didn't handle the input, then it is illegal *
 *  and should be reported to the user.                     *
 *                                                          *
 ************************************************************
 */
      else {
        pondering = 0;
        if (Option(tree) == 0)
          _printf("illegal move: %s\n", buffer);
        pondering = 1;
        display = tree->position;
      }
    } while (!move);
    if (readstat < 0 || !strcmp(args[0], "exit"))
      break;
    game_wtm = Flip(game_wtm);
    if (game_wtm)
      move_number++;
  } while (1);
  analyze_mode = 0;
  _printf("analyze complete.\n");
  pondering = 0;
  swindle_mode = save_swindle_mode;
}
Esempio n. 4
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);
}
Esempio n. 5
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) {
  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;
}
Esempio n. 6
0
/*
********************************************************************************
*                                                                              *
*  "annotate" command is used to search through the game in the "history" file *
*  (often set by the "read" command which reads moves in, skipping non-move    *
*  information such as move numbers, times, etc.)                              *
*                                                                              *
*  the normal output of this command is a file, in PGN format, that contains   *
*  the moves of the game, along with analysis when Crafty does not think that  *
*  move was the best choice.  the definition of "best choice" is somewhat      *
*  vague, because if the move played is "close" to the best move available,    *
*  Crafty will not comment on the move.  "close" is defined by the <margin>    *
*  option explained below.  this basic type of annotation works by first       *
*  using the normal tree search algorithm to find the best move.  if this      *
*  move was the move played, no output is produced.  if a different move is    *
*  considered best, then the actual move played is searched to the same depth  *
*  and if the best move and actual move scores are within <margin> of each     *
*  other, no comment is produced, otherwise crafty inserts the evaluation for  *
*  the move played, followed by the eval and PV for the best continuation it   *
*  found.                                                                      *
*                                                                              *
*  the format of the command is as follows:                                    *
*                                                                              *
*      annotate filename b|w|bw moves margin time [n]                          *
*                                                                              *
*  filename is the input file where Crafty will obtain the moves to annotate,  *
*  and output will be written to file "filename.ann".                          *
*                                                                              *
*  where b/w/bw indicates whether to annotate only the white side (w), the     *
*  black side (b) or both (bw).                                                *
*                                                                              *
*  moves indicates the move or moves to annotate.  it can be a single move,    *
*  which indicates the starting move number to annotate, or it can be a range, *
*  which indicates a range of move (1-999 gets the whole game.)                *
*                                                                              *
*  margin is the difference between Crafty's evaluation for the move actually  *
*  played and for the move Crafty thinks is best, before crafty will generate  *
*  a comment in the annotation file.  1.0 is a pawn, and will only generate    *
*  comments if the move played is 1.000 (1 pawn) worse than the best move      *
*  found by doing a complete search.                                           *
*                                                                              *
*  time is time per move to search, in seconds.                                *
*                                                                              *
*  [n] is optional and tells Crafty to produce the PV/score for the "n" best   *
*  moves.  Crafty stops when the best move reaches the move played in the game *
*  or after displaying n moves, whichever comes first.  if you use -n, then it *
*  will display n moves regardless of where the game move ranks.               *
*                                                                              *
********************************************************************************
*/
void Annotate() {

  FILE *annotate_in, *annotate_out;
  char command[80], text[128], colors[32], next;
  int annotate_margin, annotate_score[100], player_score, best_moves;
  int annotate_search_time_limit, search_player;
  int twtm, path_len, analysis_printed=0, *mv;
  int wtm, move_number, move_num, line1, line2, move, suggested, i;
  int temp_draw_score_is_zero, searches_done;
  CHESS_PATH temp[100], player_pv;

/*
 ----------------------------------------------------------
|                                                          |
|   first, quiz the user for the options needed to         |
|   successfully annotate a game.                          |
|                                                          |
 ----------------------------------------------------------
*/
  Print(0,"\nannotate filename: ");
  fscanf(input_stream,"%s",text);
  annotate_in = fopen(text,"r");
  if (annotate_in == NULL) {
    Print(0,"unable to open %s for input\n", text);
    return;
  }
  sprintf(command,"read=%s",text);
  Option(command);
  strcpy(text+strlen(text),".can");
  annotate_out = fopen(text,"w");
  if (annotate_out == NULL) {
    Print(0,"unable to open %s for output\n", text);
    return;
  }
  Print(0,"\ncolor(s): ");
  fscanf(input_stream,"%s",colors);
  line1=1;
  line2=999;
  Print(0,"\nstarting move number or range: ");
  fscanf(input_stream,"%s",text);
  if(strchr(text,'-')) sscanf(text,"%d-%d",&line1,&line2);
  else {
    sscanf(text,"%d",&line1);
    line2=999;
  }
  Print(0,"\nannotation margin: ");
  fscanf(input_stream,"%s",text);
  annotate_margin=atof(text)*PAWN_VALUE;
  Print(0,"\ntime per move: ");
  fscanf(input_stream,"%s",text);
  annotate_search_time_limit=atoi(text)*100;
  next=getc(input_stream);
  best_moves=1;
  if (next == ' ') {
    fscanf(input_stream,"%s",text);
    best_moves=atoi(text);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   reset the game to "square 0" to start the annotation   |
|   procedure.  then we read moves from the input file,    |
|   make them on the game board, and annotate if the move  |
|   is for the correct side.  if we haven't yet reached    |
|   the starting move to annotate, we skip the Search()    |
|   stuff and read another move.                           |
|                                                          |
 ----------------------------------------------------------
*/
  annotate_mode=1;
  temp_draw_score_is_zero=draw_score_is_zero;
  draw_score_is_zero=1;
  ponder_completed=0;
  ponder_move=0;
  last_pv.path_iteration_depth=0;
  last_pv.path_length=0;
  InitializeChessBoard(&position[0]);
  wtm=1;
  move_number=1;

  fprintf(annotate_out,"[Event \"%s\"]\n",pgn_event);
  fprintf(annotate_out,"[Site \"%s\"]\n",pgn_site);
  fprintf(annotate_out,"[Date \"%s\"]\n",pgn_date);
  fprintf(annotate_out,"[Round \"%s\"]\n",pgn_round);
  fprintf(annotate_out,"[White \"%s\"]\n",pgn_white);
  fprintf(annotate_out,"[WhiteElo \"%s\"]\n",pgn_white_elo);
  fprintf(annotate_out,"[Black \"%s\"]\n",pgn_black);
  fprintf(annotate_out,"[BlackElo \"%s\"]\n",pgn_black_elo);
  fprintf(annotate_out,"[Result \"%s\"]\n",pgn_result);

  fprintf(annotate_out,"[Annotator \"Crafty v%s\"]\n",version);
  if (!strcmp(colors,"bw") || !strcmp(colors,"wb"))
    fprintf(annotate_out,"{annotating both black and white moves.}\n");
  else if (strchr(colors,'b'))
    fprintf(annotate_out,"{annotating only black moves.}\n");
  else if (strchr(colors,'w'))
    fprintf(annotate_out,"{annotating only white moves.}\n");
  fprintf(annotate_out,"{using a scoring margin of %s pawns.}\n",
          DisplayEvaluationWhisper(annotate_margin));
  fprintf(annotate_out,"{search time limit is %s}\n\n",
          DisplayTimeWhisper(annotate_search_time_limit));
  do {
    fflush(annotate_out);
    move=ReadChessMove(annotate_in,wtm,0);
    if (move <= 0) break;
    strcpy(text,OutputMove(&move,0,wtm));
    fseek(history_file,((move_number-1)*2+1-wtm)*10,SEEK_SET);
    fprintf(history_file,"%10s ",text);
    if (wtm) Print(0,"White(%d): %s\n",move_number,text);
    else Print(0,"Black(%d): %s\n",move_number,text);
    if (analysis_printed)
      fprintf(annotate_out,"%3d.%s%6s\n",move_number,(wtm?"":"   ..."),text);
    else {
      if (wtm)
        fprintf(annotate_out,"%3d.%6s",move_number,text);
      else
        fprintf(annotate_out,"%6s\n",text);
    }
    analysis_printed=0;
    if (move_number >= line1) {
      if ((!wtm && strchr(colors,'b')) | ( wtm && strchr(colors,'w'))) {
        last_pv.path_iteration_depth=0;
        last_pv.path_length=0;
        thinking=1;
        RootMoveList(wtm);
/*
 ----------------------------------------------------------
|                                                          |
|   now search the position to see if the move played is   |
|   the best move possible.  if not, then search just the  |
|   move played to get a score for it as well, so we can   |
|   determine if annotated output is appropriate.          |
|                                                          |
 ----------------------------------------------------------
*/
        search_time_limit=annotate_search_time_limit;
        search_depth=0;
        player_score=-999999;
        search_player=1;
        for (searches_done=0;searches_done<abs(best_moves);searches_done++) {
          if (searches_done > 0) {
            search_time_limit=3*annotate_search_time_limit;
            search_depth=temp[0].path_iteration_depth;
          }
          Print(0,"\n              Searching all legal moves.");
          Print(0,"----------------------------------\n");
          position[1]=position[0];
          InitializeHashTables();
          annotate_score[searches_done]=Iterate(wtm,annotate);
          if (pv[0].path[1] == move) {
            player_score=annotate_score[searches_done];
            player_pv=pv[0];
            search_player=0;
          }
          temp[searches_done]=pv[0];
          for (mv=last[0];mv<last[1];mv++) {
            if (*mv == pv[0].path[1]) {
              for (;mv<last[1]-1;mv++) *mv=*(mv+1);
              last[1]--;
              break;
            }
          }
          if (last[1] < last[0] ||
              (player_score+annotate_margin>annotate_score[searches_done] &&
               best_moves>0)) break;
        }
        if (search_player) {
          Print(0,"\n              Searching only the move played in game.");
          Print(0,"--------------------\n");
          position[1]=position[0];
          search_move=move;
          search_time_limit=3*annotate_search_time_limit;
          search_depth=temp[0].path_iteration_depth;
          if (search_depth==0) search_time_limit=annotate_search_time_limit;
          InitializeHashTables();
          player_score=Iterate(wtm,annotate);
          player_pv=pv[0];
          search_depth=0;
          search_time_limit=annotate_search_time_limit;
          search_move=0;
        }
/*
 ----------------------------------------------------------
|                                                          |
|   output the score/pv for the move played unless it      |
|   matches what Crafty would have played.  if it doesn't  |
|   then output the pv for what Crafty thinks is best.     |
|                                                          |
 ----------------------------------------------------------
*/
        thinking=0;
        if (player_pv.path_iteration_depth>1 && player_pv.path_length>=1 && 
            player_score+annotate_margin<annotate_score[0] &&
            (temp[0].path[1]!=player_pv.path[1] || annotate_margin<0.0 ||
            best_moves!=1)) {
          if (wtm) {
            analysis_printed=1;
            fprintf(annotate_out,"\n");
          }
          twtm = wtm;
          fprintf(annotate_out,"                {%d:%s",
                  player_pv.path_iteration_depth,
                  DisplayEvaluationWhisper(player_score)); 
          path_len=player_pv.path_length;
          for (i=1;i<=path_len;i++) {
            fprintf(annotate_out," %s",
                    OutputMove(&player_pv.path[i],i,twtm)); 
            MakeMove(i,player_pv.path[i],twtm);
            twtm=ChangeSide(twtm);
          }
          for (i=path_len;i>0;i--) {
            twtm=ChangeSide(twtm);
            UnMakeMove(i,player_pv.path[i],twtm);
          }
          fprintf(annotate_out,"}\n");
          for (move_num=0;move_num<searches_done;move_num++) {
            twtm = wtm;
            if (move != temp[move_num].path[1]) {
              fprintf(annotate_out,"                {%d:%s",
                      temp[move_num].path_iteration_depth,
                      DisplayEvaluationWhisper(annotate_score[move_num])); 
              path_len=temp[move_num].path_length;
              for (i=1;i<=path_len;i++) {
                fprintf(annotate_out," %s",
                        OutputMove(&temp[move_num].path[i],i,twtm)); 
                MakeMove(i,temp[move_num].path[i],twtm);
                twtm=ChangeSide(twtm);
              }
              for (i=path_len;i>0;i--) {
                twtm=ChangeSide(twtm);
                UnMakeMove(i,temp[move_num].path[i],twtm);
              }
              fprintf(annotate_out,"}\n");
            }
          }
        }
      }
    }
/*
 ----------------------------------------------------------
|                                                          |
|   before going on to the next move, see if the user has  |
|   included a set of other moves that require a search.   |
|   if so, search them one at a time and produce the ana-  |
|   lysis for each one.                                    |
|                                                          |
 ----------------------------------------------------------
*/
    do {
      next=getc(annotate_in);
    } while (next==' ' || next=='\n');
    ungetc(next,annotate_in);
    if (next == EOF) break;
    if (next == '{') do {
      do {
        next=getc(annotate_in);
      } while (next==' ');
      ungetc(next,annotate_in);
      if (next == EOF || next == '}') break;
      suggested=ReadChessMove(annotate_in,wtm,1);
      if (suggested < 0) break;
      if (suggested > 0) {
        thinking=1;
        Print(0,"\n              Searching only the move suggested.");
        Print(0,"--------------------\n");
        position[1]=position[0];
        search_move=suggested;
        search_time_limit=3*annotate_search_time_limit;
        search_depth=temp[0].path_iteration_depth;
        InitializeHashTables();
        annotate_score[0]=Iterate(wtm,annotate);
        search_depth=0;
        search_time_limit=annotate_search_time_limit;
        search_move=0;
        thinking=0;
        twtm = wtm;
        path_len = pv[0].path_length;
        if (pv[0].path_iteration_depth > 1 && path_len >= 1) {
          if (wtm && !analysis_printed) {
            analysis_printed=1;
            fprintf(annotate_out,"\n");
          }
          fprintf(annotate_out,"                {suggested %d:%s",
                  pv[0].path_iteration_depth,
                  DisplayEvaluationWhisper(annotate_score[0])); 
          for (i=1;i<=path_len;i++) {
            fprintf(annotate_out," %s",OutputMove(&pv[0].path[i],i,twtm)); 
            MakeMove(i,pv[0].path[i],twtm);
            twtm=ChangeSide(twtm);
          }
          for (i=path_len;i>0;i--) {
            twtm=ChangeSide(twtm);
            UnMakeMove(i,pv[0].path[i],twtm);
          }
          fprintf(annotate_out,"}\n");
        }
      }
    } while(1);
    MakeMoveRoot(move,wtm);
    wtm=ChangeSide(wtm);
    if (wtm) move_number++;
    if (move_number > line2) break;
  } while (1);
  fprintf(annotate_out,"\n");
  if (annotate_out) fclose(annotate_out);
  if (annotate_in) fclose(annotate_in);
  search_time_limit=0;
  draw_score_is_zero=temp_draw_score_is_zero;
  annotate_mode=0;
}