home *** CD-ROM | disk | FTP | other *** search
/ Dream 57 / Amiga_Dream_57.iso / Amiga / Jeux / Reflexion / Crafty-15.19.lha / crafty-15.19 / src / annotate.c < prev    next >
C/C++ Source or Header  |  1998-09-13  |  17KB  |  363 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include "chess.h"
  5. #include "data.h"
  6.  
  7. /* last modified 02/17/98 */
  8. /*
  9. ********************************************************************************
  10. *                                                                              *
  11. *  "annotate" command is used to search through the game in the "history" file *
  12. *  (often set by the "read" command which reads moves in, skipping non-move    *
  13. *  information such as move numbers, times, etc.)                              *
  14. *                                                                              *
  15. *  the normal output of this command is a file, in PGN format, that contains   *
  16. *  the moves of the game, along with analysis when Crafty does not think that  *
  17. *  move was the best choice.  the definition of "best choice" is somewhat      *
  18. *  vague, because if the move played is "close" to the best move available,    *
  19. *  Crafty will not comment on the move.  "close" is defined by the <margin>    *
  20. *  option explained below.  this basic type of annotation works by first       *
  21. *  using the normal tree search algorithm to find the best move.  if this      *
  22. *  move was the move played, no output is produced.  if a different move is    *
  23. *  considered best, then the actual move played is searched to the same depth  *
  24. *  and if the best move and actual move scores are within <margin> of each     *
  25. *  other, no comment is produced, otherwise crafty inserts the evaluation for  *
  26. *  the move played, followed by the eval and PV for the best continuation it   *
  27. *  found.  you can enter suggested moves for Crafty to analyze at any point    *
  28. *  by simply entering a move as an analysis-type comment using (move) or       *
  29. *  {move}.  Crafty will search that move in addition to the move actually      *
  30. *  played and the move it thinks is best.                                      *
  31. *                                                                              *
  32. *  the format of the command is as follows:                                    *
  33. *                                                                              *
  34. *      annotate filename b|w|bw moves margin time [n]                          *
  35. *                                                                              *
  36. *  filename is the input file where Crafty will obtain the moves to annotate,  *
  37. *  and output will be written to file "filename.ann".                          *
  38. *                                                                              *
  39. *  where b/w/bw indicates whether to annotate only the white side (w), the     *
  40. *  black side (b) or both (bw).                                                *
  41. *                                                                              *
  42. *  moves indicates the move or moves to annotate.  it can be a single move,    *
  43. *  which indicates the starting move number to annotate, or it can be a range, *
  44. *  which indicates a range of move (1-999 gets the whole game.)                *
  45. *                                                                              *
  46. *  margin is the difference between Crafty's evaluation for the move actually  *
  47. *  played and for the move Crafty thinks is best, before crafty will generate  *
  48. *  a comment in the annotation file.  1.0 is a pawn, and will only generate    *
  49. *  comments if the move played is 1.000 (1 pawn) worse than the best move      *
  50. *  found by doing a complete search.                                           *
  51. *                                                                              *
  52. *  time is time per move to search, in seconds.                                *
  53. *                                                                              *
  54. *  [n] is optional and tells Crafty to produce the PV/score for the "n" best   *
  55. *  moves.  Crafty stops when the best move reaches the move played in the game *
  56. *  or after displaying n moves, whichever comes first.  if you use -n, then it *
  57. *  will display n moves regardless of where the game move ranks.               *
  58. *                                                                              *
  59. ********************************************************************************
  60. */
  61. void Annotate() {
  62.  
  63.   FILE *annotate_in, *annotate_out;
  64.   char text[128], tbuffer[512], colors[32];
  65.   int annotate_margin, annotate_score[100], player_score, best_moves;
  66.   int annotate_search_time_limit, search_player;
  67.   int twtm, path_len, analysis_printed=0, *mv;
  68.   int wtm, move_num, line1, line2, move, suggested, i;
  69.   int searches_done, read_status;
  70.   PATH temp[100], player_pv;
  71.   int temp_search_depth;
  72.   TREE *tree=local[0];
  73. /*
  74.  ----------------------------------------------------------
  75. |                                                          |
  76. |   first, quiz the user for the options needed to         |
  77. |   successfully annotate a game.                          |
  78. |                                                          |
  79.  ----------------------------------------------------------
  80. */
  81.   strcpy(tbuffer,buffer);
  82.   nargs=ReadParse(tbuffer,args,"     ;");
  83.   if (nargs < 6) {
  84.     printf("usage: annotate <file> <color> <moves> <margin> <time> [nmoves]\n");
  85.     return;
  86.   }
  87.   annotate_in = fopen(args[1],"r");
  88.   if (annotate_in == NULL) {
  89.     Print(4095,"unable to open %s for input\n", args[1]);
  90.     return;
  91.   }
  92.   nargs=ReadParse(tbuffer,args,"     ;");
  93.   strcpy(text,args[1]);
  94.   strcpy(text+strlen(text),".can");
  95.   annotate_out = fopen(text,"w");
  96.   if (annotate_out == NULL) {
  97.     Print(4095,"unable to open %s for output\n", text);
  98.     return;
  99.   }
  100.   draw_score_normal=1;
  101.   strcpy(colors,args[2]);
  102.   line1=1;
  103.   line2=999;
  104.   if(strchr(args[3],'-')) sscanf(args[3],"%d-%d",&line1,&line2);
  105.   else {
  106.     sscanf(args[3],"%d",&line1);
  107.     line2=999;
  108.   }
  109.   annotate_margin=atof(args[4])*PAWN_VALUE;
  110.   annotate_search_time_limit=atoi(args[5])*100;
  111.   if (nargs > 6) 
  112.     best_moves=atoi(args[6]);
  113.   else
  114.     best_moves=1;
  115. /*
  116.  ----------------------------------------------------------
  117. |                                                          |
  118. |   reset the game to "square 0" to start the annotation   |
  119. |   procedure.  then we read moves from the input file,    |
  120. |   make them on the game board, and annotate if the move  |
  121. |   is for the correct side.  if we haven't yet reached    |
  122. |   the starting move to annotate, we skip the Search()    |
  123. |   stuff and read another move.                           |
  124. |                                                          |
  125.  ----------------------------------------------------------
  126. */
  127.   annotate_mode=1;
  128.   ponder=0;
  129.   temp_search_depth=search_depth;
  130.  
  131.   read_status=ReadPGN(0,0);
  132.   read_status=ReadPGN(annotate_in,0);
  133.   while (read_status != -1) {
  134.     ponder_move=0;
  135.     last_pv.path_iteration_depth=0;
  136.     last_pv.path_length=0;
  137.     InitializeChessBoard(&tree->position[0]);
  138.     tree->position[1]=tree->position[0];
  139.     wtm=1;
  140.     move_number=1;
  141. /*
  142.  ----------------------------------------------------------
  143. |                                                          |
  144. |   now grab the PGN tag values so they can be copied to   |
  145. |   the .can file for reference.                           |
  146. |                                                          |
  147.  ----------------------------------------------------------
  148. */
  149.     do
  150.       read_status=ReadPGN(annotate_in,0);
  151.     while(read_status==1);
  152.     if (read_status == -1) break;
  153.     fprintf(annotate_out,"[Event \"%s\"]\n",pgn_event);
  154.     fprintf(annotate_out,"[Site \"%s\"]\n",pgn_site);
  155.     fprintf(annotate_out,"[Date \"%s\"]\n",pgn_date);
  156.     fprintf(annotate_out,"[Round \"%s\"]\n",pgn_round);
  157.     fprintf(annotate_out,"[White \"%s\"]\n",pgn_white);
  158.     fprintf(annotate_out,"[WhiteElo \"%s\"]\n",pgn_white_elo);
  159.     fprintf(annotate_out,"[Black \"%s\"]\n",pgn_black);
  160.     fprintf(annotate_out,"[BlackElo \"%s\"]\n",pgn_black_elo);
  161.     fprintf(annotate_out,"[Result \"%s\"]\n",pgn_result);
  162.  
  163.     fprintf(annotate_out,"[Annotator \"Crafty v%s\"]\n",version);
  164.     if (!strcmp(colors,"bw") || !strcmp(colors,"wb"))
  165.       fprintf(annotate_out,"{annotating both black and white moves.}\n");
  166.     else if (strchr(colors,'b'))
  167.       fprintf(annotate_out,"{annotating only black moves.}\n");
  168.     else if (strchr(colors,'w'))
  169.       fprintf(annotate_out,"{annotating only white moves.}\n");
  170.     fprintf(annotate_out,"{using a scoring margin of %s pawns.}\n",
  171.             DisplayEvaluationWhisper(annotate_margin));
  172.     fprintf(annotate_out,"{search time limit is %s}\n\n",
  173.             DisplayTimeWhisper(annotate_search_time_limit));
  174.     do {
  175.       fflush(annotate_out);
  176.       move=ReadNextMove(tree,buffer,0,wtm);
  177.       if (move <= 0) break;
  178.       strcpy(text,OutputMove(tree,move,0,wtm));
  179.       fseek(history_file,((move_number-1)*2+1-wtm)*10,SEEK_SET);
  180.       fprintf(history_file,"%9s\n",text);
  181.       if (wtm) Print(4095,"White(%d): %s\n",move_number,text);
  182.       else Print(4095,"Black(%d): %s\n",move_number,text);
  183.       if (analysis_printed)
  184.         fprintf(annotate_out,"%3d.%s%6s\n",move_number,(wtm?"":"   ..."),text);
  185.       else {
  186.         if (wtm)
  187.           fprintf(annotate_out,"%3d.%6s",move_number,text);
  188.         else
  189.           fprintf(annotate_out,"%6s\n",text);
  190.       }
  191.       analysis_printed=0;
  192.       if (move_number >= line1) {
  193.         if ((!wtm && strchr(colors,'b')) || ( wtm && strchr(colors,'w'))) {
  194.           last_pv.path_iteration_depth=0;
  195.           last_pv.path_length=0;
  196.           thinking=1;
  197.           RootMoveList(wtm);
  198. /*
  199.  ----------------------------------------------------------
  200. |                                                          |
  201. |   now search the position to see if the move played is   |
  202. |   the best move possible.  if not, then search just the  |
  203. |   move played to get a score for it as well, so we can   |
  204. |   determine if annotated output is appropriate.          |
  205. |                                                          |
  206.  ----------------------------------------------------------
  207. */
  208.           search_time_limit=annotate_search_time_limit;
  209.           search_depth=temp_search_depth;
  210.           player_score=-999999;
  211.           search_player=1;
  212.           for (searches_done=0;searches_done<abs(best_moves);searches_done++) {
  213.             if (searches_done > 0) {
  214.               search_time_limit=3*annotate_search_time_limit;
  215.               search_depth=temp[0].path_iteration_depth;
  216.             }
  217.             Print(4095,"\n              Searching all legal moves.");
  218.             Print(4095,"----------------------------------\n");
  219.             tree->position[1]=tree->position[0];
  220.             InitializeHashTables();
  221.             annotate_score[searches_done]=Iterate(wtm,annotate,1);
  222.             if (tree->pv[0].path[1] == move) {
  223.               player_score=annotate_score[searches_done];
  224.               player_pv=tree->pv[0];
  225.               search_player=0;
  226.             }
  227.             temp[searches_done]=tree->pv[0];
  228.             for (mv=tree->last[0];mv<tree->last[1];mv++) {
  229.               if (*mv == tree->pv[0].path[1]) {
  230.                 for (;mv<tree->last[1]-1;mv++) *mv=*(mv+1);
  231.                 tree->last[1]--;
  232.                 break;
  233.               }
  234.             }
  235.             if (tree->last[1] < tree->last[0] ||
  236.                 (player_score+annotate_margin>annotate_score[searches_done] &&
  237.                  best_moves>0)) break;
  238.           }
  239.           if (search_player) {
  240.             Print(4095,"\n              Searching only the move played in game.");
  241.             Print(4095,"--------------------\n");
  242.             tree->position[1]=tree->position[0];
  243.             search_move=move;
  244.             search_time_limit=3*annotate_search_time_limit;
  245.             search_depth=temp[0].path_iteration_depth;
  246.             if (search_depth==temp_search_depth)
  247.               search_time_limit=annotate_search_time_limit;
  248.             InitializeHashTables();
  249.             player_score=Iterate(wtm,annotate,0);
  250.             player_pv=tree->pv[0];
  251.             search_depth=temp_search_depth;
  252.             search_time_limit=annotate_search_time_limit;
  253.             search_move=0;
  254.           }
  255. /*
  256.  ----------------------------------------------------------
  257. |                                                          |
  258. |   output the score/pv for the move played unless it      |
  259. |   matches what Crafty would have played.  if it doesn't  |
  260. |   then output the pv for what Crafty thinks is best.     |
  261. |                                                          |
  262.  ----------------------------------------------------------
  263. */
  264.           thinking=0;
  265.           if (player_pv.path_iteration_depth>1 && player_pv.path_length>=1 && 
  266.               player_score+annotate_margin<annotate_score[0] &&
  267.               (temp[0].path[1]!=player_pv.path[1] || annotate_margin<0.0 ||
  268.               best_moves!=1)) {
  269.             if (wtm) {
  270.               analysis_printed=1;
  271.               fprintf(annotate_out,"\n");
  272.             }
  273.             fprintf(annotate_out,"                ({%d:%s}",
  274.                     player_pv.path_iteration_depth,
  275.                     DisplayEvaluationWhisper(player_score)); 
  276.             path_len=player_pv.path_length;
  277.             fprintf(annotate_out," %s", FormatPV(tree,wtm, player_pv));
  278.             fprintf(annotate_out,")\n");
  279.             for (move_num=0;move_num<searches_done;move_num++) {
  280.               if (move != temp[move_num].path[1]) {
  281.                 fprintf(annotate_out,"                ({%d:%s}",
  282.                         temp[move_num].path_iteration_depth,
  283.                         DisplayEvaluationWhisper(annotate_score[move_num])); 
  284.                 path_len=temp[move_num].path_length;
  285.                 fprintf(annotate_out," %s", FormatPV(tree,wtm, temp[move_num]));
  286.                 fprintf(annotate_out,")\n");
  287.               }
  288.             }
  289.           }
  290.         }
  291.       }
  292. /*
  293.  ----------------------------------------------------------
  294. |                                                          |
  295. |   before going on to the next move, see if the user has  |
  296. |   included a set of other moves that require a search.   |
  297. |   if so, search them one at a time and produce the ana-  |
  298. |   lysis for each one.                                    |
  299. |                                                          |
  300.  ----------------------------------------------------------
  301. */
  302.       read_status=ReadPGN(annotate_in,1);
  303.       while (read_status == 2) {
  304.         suggested=InputMove(tree,buffer,0,wtm,1,0);
  305.         if (suggested > 0) {
  306.           thinking=1;
  307.           Print(4095,"\n              Searching only the move suggested.");
  308.           Print(4095,"--------------------\n");
  309.           tree->position[1]=tree->position[0];
  310.           search_move=suggested;
  311.           search_time_limit=3*annotate_search_time_limit;
  312.           search_depth=temp[0].path_iteration_depth;
  313.           InitializeHashTables();
  314.           annotate_score[0]=Iterate(wtm,annotate,0);
  315.           search_depth=temp_search_depth;
  316.           search_time_limit=annotate_search_time_limit;
  317.           search_move=0;
  318.           thinking=0;
  319.           twtm = wtm;
  320.           path_len = tree->pv[0].path_length;
  321.           if (tree->pv[0].path_iteration_depth > 1 && path_len >= 1) {
  322.             if (wtm && !analysis_printed) {
  323.               analysis_printed=1;
  324.               fprintf(annotate_out,"\n");
  325.             }
  326.             fprintf(annotate_out,"                ({suggested %d:%s}",
  327.                     tree->pv[0].path_iteration_depth,
  328.                     DisplayEvaluationWhisper(annotate_score[0])); 
  329.             for (i=1;i<=path_len;i++) {
  330.               fprintf(annotate_out," %s",OutputMove(tree,tree->pv[0].path[i],i,twtm)); 
  331.               MakeMove(tree,i,tree->pv[0].path[i],twtm);
  332.               twtm=ChangeSide(twtm);
  333.               }
  334.             for (i=path_len;i>0;i--) {
  335.               twtm=ChangeSide(twtm);
  336.               UnMakeMove(tree,i,tree->pv[0].path[i],twtm);
  337.             }
  338.             fprintf(annotate_out,")\n");
  339.           }
  340.         }
  341.         read_status=ReadPGN(annotate_in,1);
  342.         if (read_status != 2) break;
  343.       }
  344.       MakeMoveRoot(tree,move,wtm);
  345.       wtm=ChangeSide(wtm);
  346.       if (wtm) move_number++;
  347.       if (move_number > line2) break;
  348.       if (read_status != 0) break;
  349.     } while (1);
  350.     fprintf(annotate_out,"\n");
  351.     if (read_status == -1) break;
  352.     do
  353.       read_status=ReadPGN(annotate_in,0);
  354.     while(read_status==0);
  355.     if (read_status == -1) break;
  356.   }
  357.   fprintf(annotate_out,"\n");
  358.   if (annotate_out) fclose(annotate_out);
  359.   if (annotate_in) fclose(annotate_in);
  360.   search_time_limit=0;
  361.   annotate_mode=0;
  362. }
  363.