void Initialize(int continuing)
{
/*
 ----------------------------------------------------------
|                                                          |
|   perform routine initialization.                        |
|                                                          |
 ----------------------------------------------------------
*/
  int i=0;

  InitializeZeroMasks();
  InitializeMasks();
  InitializeRandomHash();
  InitializeAttackBoards();
  InitializePawnMasks();
  InitializePieceMasks();
  InitializeChessBoard(&position[0]);
#if defined(NT_i386) || defined(NT_AXP)
  _fmode = _O_BINARY;  /* set global file mode to binary to avoid text translation */
#endif

  last[0]=move_list;
  if (continuing) {
    history_file=fopen("game.001","r+");
    if (!log_file || !history_file) {
      printf("\nsorry.  nothing to continue.\n\n");
      history_file=fopen("game.001","w+");
    }
    else {
      sprintf(buffer,"read game.001");
      (void) Option();
    }
  }
  else {
    history_file=fopen("game.001","w+");
  }

  trans_ref_wa=(HASH_ENTRY*)malloc(16*hash_table_size);
  trans_ref_wb=(HASH_ENTRY*)malloc(16*2*hash_table_size);
  trans_ref_ba=(HASH_ENTRY*)malloc(16*hash_table_size);
  trans_ref_bb=(HASH_ENTRY*)malloc(16*2*hash_table_size);
  pawn_hash_table=(PAWN_HASH_ENTRY*)malloc(sizeof(PAWN_HASH_ENTRY)*pawn_hash_table_size);
  InitializeHashTables();
  if (!trans_ref_wa || !trans_ref_wb || !trans_ref_ba || !trans_ref_bb ) {
    printf("malloc() failed, not enough memory.\n");
    free(trans_ref_wa);
    free(trans_ref_wb);
    free(trans_ref_ba);
    free(trans_ref_bb);
    free(pawn_hash_table);
    hash_table_size=0;
    pawn_hash_table_size=0;
    log_hash=0;
    log_pawn_hash=0;
    trans_ref_wa=0;
    trans_ref_wb=0;
    trans_ref_ba=0;
    trans_ref_bb=0;
    pawn_hash_table=0;
  }
  hash_maska=(1<<log_hash)-1;
  hash_maskb=(1<<(log_hash+1))-1;
  pawn_hash_mask=((unsigned int) 037777777777)>>(32-log_pawn_hash);
}
Example #2
0
/*
 *******************************************************************************
 *                                                                             *
 *   SetBoard() is used to set up the board in any position desired.  It uses  *
 *   a forsythe-like string of characters to describe the board position.      *
 *                                                                             *
 *   The standard piece codes p,n,b,r,q,k are used to denote the type of piece *
 *   on a square, upper/lower case are used to indicate the side (program/opp.)*
 *   of the piece.                                                             *
 *                                                                             *
 *   The pieces are entered with square a8 first, then b8, ... until the full  *
 *   8th rank is completed.  A "/" terminates that rank.  This is repeated for *
 *   each of the 8 ranks, with the last (1st) rank not needing a terminating   *
 *   "/".  For empty squares, a number between 1 and 8 can be used to indicate *
 *   the number of adjacent empty squares.                                     *
 *                                                                             *
 *   That board description must be followed by a "b" or "w" to indicate which *
 *   side is on move.                                                          *
 *                                                                             *
 *   Next, up to 4 characters are used to indicate which side can castle and   *
 *   to which side.  An uppercase K means white can castle kingside, while a   *
 *   lowercase q means black can castle queenside.                             *
 *                                                                             *
 *   Finally, if there is an enpassant capture possible (the last move was a   *
 *   double pawn move and there was an enemy pawn that could capture it.  The  *
 *   square is the square the capturing pawn ends up on.                       *
 *                                                                             *
 *         K2R/PPP////q/5ppp/7k/ b - -                                         *
 *                                                                             *
 *   this assumes that k represents a white king and -q represents a black     *
 *   queen.                                                                    *
 *                                                                             *
 *                          k  *  *  r  *  *  *  *                             *
 *                          p  p  p  *  *  *  *  *                             *
 *                          *  *  *  *  *  *  *  *                             *
 *                          *  *  *  *  *  *  *  *                             *
 *                          *  *  *  *  *  *  *  *                             *
 *                         -q  *  *  *  *  *  *  *                             *
 *                          *  *  *  *  * -p -p -p                             *
 *                          *  *  *  *  *  *  * -k                             *
 *                                                                             *
 *******************************************************************************
 */
void SetBoard(TREE * tree, int nargs, char *args[], int special) {
  int twtm, i, match, num, pos, square, tboard[64];
  int bcastle, ep, wcastle, error = 0;
  char input[80];
  static const char bdinfo[] =
      { 'k', 'q', 'r', 'b', 'n', 'p', '*', 'P', 'N', 'B',
    'R', 'Q', 'K', '*', '1', '2', '3', '4',
    '5', '6', '7', '8', '/'
  };
  static const char status[13] =
      { 'K', 'Q', 'k', 'q', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
    'h', ' '
  };
  int whichsq;
  static const int firstsq[8] = { 56, 48, 40, 32, 24, 16, 8, 0 };
  if (special)
    strcpy(input, initial_position);
  else
    strcpy(input, args[0]);
  for (i = 0; i < 64; i++)
    tboard[i] = 0;
/*
 ************************************************************
 *                                                          *
 *   Scan the input string searching for pieces, numbers    *
 *   [empty squares], slashes [end-of-rank] and a blank     *
 *   [end of board, start of castle status].                *
 *                                                          *
 ************************************************************
 */
  whichsq = 0;
  square = firstsq[whichsq];
  num = 0;
  for (pos = 0; pos < (int) strlen(args[0]); pos++) {
    for (match = 0; match < 23 && args[0][pos] != bdinfo[match]; match++);
    if (match > 22)
      break;
/*
 "/" -> end of this rank.
 */
    else if (match == 22) {
      num = 0;
      if (whichsq > 6)
        break;
      square = firstsq[++whichsq];
    }
/*
 "1-8" -> empty squares.
 */
    else if (match >= 14) {
      num += match - 13;
      square += match - 13;
      if (num > 8) {
        printf("more than 8 squares on one rank\n");
        error = 1;
        break;
      }
      continue;
    }
/*
 piece codes.
 */
    else {
      if (++num > 8) {
        printf("more than 8 squares on one rank\n");
        error = 1;
        break;
      }
      tboard[square++] = match - 6;
    }
  }
/*
 ************************************************************
 *                                                          *
 *   Now extract (a) side to move [w/b], (b) castle status  *
 *   [KkQq for white/black king-side ok, white/black queen- *
 *   side ok], (c) enpassant target square.                 *
 *                                                          *
 ************************************************************
 */
  twtm = 0;
  ep = 0;
  wcastle = 0;
  bcastle = 0;
/*
 ************************************************************
 *                                                          *
 *   Side to move.                                          *
 *                                                          *
 ************************************************************
 */
  if (args[1][0] == 'w')
    twtm = 1;
  else if (args[1][0] == 'b')
    twtm = 0;
  else {
    printf("side to move is bad\n");
    error = 1;
  }
/*
 ************************************************************
 *                                                          *
 *   Castling/enpassant status.                             *
 *                                                          *
 ************************************************************
 */
  if (nargs > 2 && strlen(args[2])) {
    if (strcmp(args[2], "-")) {
      for (pos = 0; pos < (int) strlen(args[2]); pos++) {
        for (match = 0; (match < 13) && (args[2][pos] != status[match]);
            match++);
        if (match == 0)
          wcastle += 1;
        else if (match == 1)
          wcastle += 2;
        else if (match == 2)
          bcastle += 1;
        else if (match == 3)
          bcastle += 2;
        else if (args[2][0] != '-') {
          printf("castling status is bad.\n");
          error = 1;
        }
      }
    }
  }
  if (nargs > 3 && strlen(args[3])) {
    if (strcmp(args[3], "-")) {
      if (args[3][0] >= 'a' && args[3][0] <= 'h' && args[3][1] > '0' &&
          args[3][1] < '9') {
        ep = (args[3][1] - '1') * 8 + args[3][0] - 'a';
      } else if (args[3][0] != '-') {
        printf("enpassant status is bad.\n");
        error = 1;
      }
    }
  }
  for (i = 0; i < 64; i++)
    PcOnSq(i) = tboard[i];
  Castle(0, white) = wcastle;
  Castle(0, black) = bcastle;
  EnPassant(0) = 0;
  if (ep) {
    if (Rank(ep) == RANK6) {
      if (PcOnSq(ep - 8) != -pawn)
        ep = 0;
    } else if (Rank(ep) == RANK3) {
      if (PcOnSq(ep + 8) != pawn)
        ep = 0;
    } else
      ep = 0;
    if (!ep) {
      printf("enpassant status is bad (must be on 3rd/6th rank only.\n");
      ep = 0;
      error = 1;
    }
    EnPassant(0) = ep;
  }
  Rule50Moves(0) = 0;
/*
 ************************************************************
 *                                                          *
 *   Now check the castling status and enpassant status to  *
 *   make sure that the board is in a state that matches    *
 *   these.                                                 *
 *                                                          *
 ************************************************************
 */
  if (((Castle(0, white) & 2) && (PcOnSq(A1) != rook)) ||
      ((Castle(0, white) & 1) && (PcOnSq(H1) != rook)) ||
      ((Castle(0, black) & 2) && (PcOnSq(A8) != -rook)) ||
      ((Castle(0, black) & 1) && (PcOnSq(H8) != -rook))) {
    printf("ERROR-- castling status does not match board position\n");
    error = 1;
  }
/*
 ************************************************************
 *                                                          *
 *   Now set the bitboards so that error tests can be done. *
 *                                                          *
 ************************************************************
 */
  if ((twtm && EnPassant(0) && (PcOnSq(EnPassant(0) + 8) != -pawn) &&
          (PcOnSq(EnPassant(0) - 7) != pawn) &&
          (PcOnSq(EnPassant(0) - 9) != pawn)) || (Flip(twtm) && EnPassant(0)
          && (PcOnSq(EnPassant(0) - 8) != pawn) &&
          (PcOnSq(EnPassant(0) + 7) != -pawn) &&
          (PcOnSq(EnPassant(0) + 9) != -pawn))) {
    EnPassant(0) = 0;
  }
  SetChessBitBoards(tree);
/*
 ************************************************************
 *                                                          *
 *   Now check the position for a sane position, which      *
 *   means no more than 8 pawns, no more than 10 knights,   *
 *   bishops or rooks, no more than 9 queens, no pawns on   *
 *   1st or 8th rank, etc.                                  *
 *                                                          *
 ************************************************************
 */
  wtm = twtm;
  error += InvalidPosition(tree);
  if (!error) {
    if (log_file)
      DisplayChessBoard(log_file, tree->pos);
    tree->rep_index[white] = 0;
    tree->rep_index[black] = 0;
    Rule50Moves(0) = 0;
    if (!special) {
      last_mate_score = 0;
      InitializeKillers();
      last_pv.pathd = 0;
      last_pv.pathl = 0;
      tree->pv[0].pathd = 0;
      tree->pv[0].pathl = 0;
      moves_out_of_book = 0;
    }
  } else {
    if (special)
      Print(4095, "bad string = \"%s\"\n", initial_position);
    else
      Print(4095, "bad string = \"%s\"\n", args[0]);
    InitializeChessBoard(tree);
    Print(4095, "Illegal position, using normal initial chess position\n");
  }
}
Example #3
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;
}