Subversion Repositories Games.Chess Giants

Rev

Rev 33 | Rev 154 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. #include "chess.h"
  2. #include "data.h"
  3. /* last modified 02/26/14 */
  4. /*
  5.  *******************************************************************************
  6.  *                                                                             *
  7.  *   "annotate" command is used to search through the game in a pgn file, and  *
  8.  *   provide a qualitative analysis of each move played and then creating a    *
  9.  *   new output file (xxx.can) containing the original game + new commentary.  *
  10.  *                                                                             *
  11.  *   The normal output of this command is a file, in PGN format, that contains *
  12.  *   the moves of the game, along with analysis when Crafty does not think     *
  13.  *   that move was the best choice.  The definition of "best choice" is        *
  14.  *   somewhat vague, because if the move played is "close" to the best move    *
  15.  *   available, Crafty will not comment on the move.  "Close" is defined by    *
  16.  *   the <margin> option explained below.  This basic type of annotation works *
  17.  *   by first using the normal tree search algorithm to find the best move.    *
  18.  *   If this move was the move played, no output is produced.  If a different  *
  19.  *   move is considered best, then the actual move played is searched to the   *
  20.  *   same depth and if the best move and actual move scores are within         *
  21.  *   <margin> of each other, no comment is produced, otherwise Crafty inserts  *
  22.  *   the evaluation for the move played, followed by the eval and PV for the   *
  23.  *   best continuation it found.  You can enter suggested moves for Crafty to  *
  24.  *   analyze at any point by simply entering a move as an analysis-type        *
  25.  *   comment using (move) or {move}.  Crafty will search that move in addition *
  26.  *   to the move actually played and the move it thinks is best.               *
  27.  *                                                                             *
  28.  *   The format of the command is as follows:                                  *
  29.  *                                                                             *
  30.  *        annotate filename b|w|bw|name moves margin time [n]                  *
  31.  *                                                                             *
  32.  *   Filename is the input file where Crafty will obtain the moves to          *
  33.  *   annotate, and output will be written to file "filename.can".              *
  34.  *                                                                             *
  35.  *        annotateh filename b|w|bw|name moves margin time [n]                 *
  36.  *                                                                             *
  37.  *   Can be used to produce an HTML-compatible file that includes bitmapped    *
  38.  *   diagrams of the positions where Crafty provides analysis.  This file can  *
  39.  *   be opened by a browser to provide much easier 'reading'.                  *
  40.  *                                                                             *
  41.  *        annotatet filename b|w|bw|name moves margin time [n]                 *
  42.  *                                                                             *
  43.  *   Can be used to produce a LaTeX-compatible file that includes LaTeX chess  *
  44.  *   fonts.  This file can be read/printed by any program that can handle      *
  45.  *   LaTeX input.                                                              *
  46.  *                                                                             *
  47.  *   Where b/w/bw indicates whether to annotate only the white side (w), the   *
  48.  *   black side (b) or both (bw).  You can also specify a name (or part of a   *
  49.  *   name, just be sure it is unique in the name tags for clarity in who you   *
  50.  *   mean).                                                                    *
  51.  *                                                                             *
  52.  *   Moves indicates the move or moves to annotate.  It can be a single move,  *
  53.  *   which indicates the starting move number to annotate, or it can be a      *
  54.  *   range, which indicates a range of move (1-999 gets the whole game.)       *
  55.  *                                                                             *
  56.  *   Margin is the difference between Crafty's evaluation for the move         *
  57.  *   actually played and for the move Crafty thinks is best, before Crafty     *
  58.  *   will generate a comment in the annotation file.  1.0 is a pawn, and will  *
  59.  *   only generate comments if the move played is 1.000 (1 pawn) worse than    *
  60.  *   the best move found by doing a complete search.                           *
  61.  *                                                                             *
  62.  *   Time is time per move to search, in seconds.                              *
  63.  *                                                                             *
  64.  *   [n] is optional and tells Crafty to produce the PV/score for the "n" best *
  65.  *   moves.  Crafty stops when the best move reaches the move played in the    *
  66.  *   game or after displaying n moves, whichever comes first.  If you use -n,  *
  67.  *   then it will display n moves regardless of where the game move ranks.     *
  68.  *                                                                             *
  69.  *******************************************************************************
  70.  */
  71. #define MIN_DECISIVE_ADV 150
  72. #define MIN_MODERATE_ADV  70
  73. #define MIN_SLIGHT_ADV    30
  74. void Annotate() {
  75.   FILE *annotate_in, *annotate_out;
  76.   char text[128], tbuffer[4096], colors[32] = { "" }, pname[128] = {
  77.   ""};
  78.   int annotate_margin, annotate_score[100], player_score, best_moves,
  79.       annotate_wtm;
  80.   int annotate_search_time_limit, search_player;
  81.   int twtm, path_len, analysis_printed = 0;
  82.   int wtm, move_num, line1, line2, move, suggested, i;
  83.   int searches_done, read_status;
  84.   PATH temp[100], player_pv;
  85.   int temp_search_depth;
  86.   TREE *const tree = block[0];
  87.   char html_br[5] = { "" };
  88.   int save_swindle_mode;
  89.   int html_mode = 0;
  90.   int latex = 0;
  91.  
  92. /*
  93.  ************************************************************
  94.  *                                                          *
  95.  *  First, extract the options from the command line to     *
  96.  *  determine what the user wanted us to do.                *
  97.  *                                                          *
  98.  ************************************************************
  99.  */
  100.   save_swindle_mode = swindle_mode;
  101.   if (!strcmp(args[0], "annotateh")) {
  102.     html_mode = 1;
  103.     strcpy(html_br, "<br>");
  104.   }
  105.   if (!strcmp(args[0], "annotatet")) {
  106.     latex = 1;
  107.     strcpy(html_br, "\\\\");
  108.   }
  109.   strcpy(tbuffer, buffer);
  110.   nargs = ReadParse(tbuffer, args, " \t;");
  111.   if (nargs < 6) {
  112.     printf
  113.         ("usage: annotate <file> <color> <moves> <margin> <time> [nmoves]\n");
  114.     return;
  115.   }
  116.   annotate_in = fopen(args[1], "r");
  117.   if (annotate_in == NULL) {
  118.     Print(4095, "unable to open %s for input\n", args[1]);
  119.     return;
  120.   }
  121.   nargs = ReadParse(tbuffer, args, " \t;");
  122.   strcpy(text, args[1]);
  123.   if (html_mode == 1)
  124.     strcpy(text + strlen(text), ".html");
  125.   else if (latex == 1)
  126.     strcpy(text + strlen(text), ".tex");
  127.   else
  128.     strcpy(text + strlen(text), ".can");
  129.   annotate_out = fopen(text, "w");
  130.   if (annotate_out == NULL) {
  131.     Print(4095, "unable to open %s for output\n", text);
  132.     return;
  133.   }
  134.   if (html_mode == 1)
  135.     AnnotateHeaderHTML(text, annotate_out);
  136.   if (latex == 1)
  137.     AnnotateHeaderTeX(annotate_out);
  138.   if (strlen(args[2]) <= 2)
  139.     strcpy(colors, args[2]);
  140.   else
  141.     strcpy(pname, args[2]);
  142.   line1 = 1;
  143.   line2 = 999;
  144.   if (strchr(args[3], 'b'))
  145.     line2 = -1;
  146.   if (strchr(args[3], '-'))
  147.     sscanf(args[3], "%d-%d", &line1, &line2);
  148.   else {
  149.     sscanf(args[3], "%d", &line1);
  150.     line2 = 999;
  151.   }
  152.   annotate_margin = (int) (atof(args[4]) * PieceValues(white, pawn)); // Pierre-Marie Baty -- added type cast
  153.   annotate_search_time_limit = (int) (atof(args[5]) * 100); // Pierre-Marie Baty -- added type cast
  154.   if (nargs > 6)
  155.     best_moves = atoi(args[6]);
  156.   else
  157.     best_moves = 1;
  158. /*
  159.  ************************************************************
  160.  *                                                          *
  161.  *  Reset the game to "square 0" to start the annotation    *
  162.  *  procedure.  Then we read moves from the input file,     *
  163.  *  make them on the game board, and annotate if the move   *
  164.  *  is for the correct side.  If we haven't yet reached the *
  165.  *  starting move to annotate, we skip the Search() stuff   *
  166.  *   and read another move.                                 *
  167.  *                                                          *
  168.  ************************************************************
  169.  */
  170.   annotate_mode = 1;
  171.   swindle_mode = 0;
  172.   ponder = 0;
  173.   temp_search_depth = search_depth;
  174.   read_status = ReadPGN(0, 0);
  175.   read_status = ReadPGN(annotate_in, 0);
  176.   player_pv.path[1] = 0;
  177.   while (read_status != -1) {
  178.     ponder_move = 0;
  179.     last_pv.pathd = 0;
  180.     last_pv.pathl = 0;
  181.     player_pv.pathd = 0;
  182.     player_pv.pathl = 0;
  183.     tree->pv[0].pathl = 0;
  184.     tree->pv[0].pathd = 0;
  185.     analysis_printed = 0;
  186.     InitializeChessBoard(tree);
  187.     tree->status[1] = tree->status[0];
  188.     wtm = 1;
  189.     move_number = 1;
  190. /*
  191.  ************************************************************
  192.  *                                                          *
  193.  *  Now grab the PGN tag values so they can be copied to    *
  194.  *  the .can file for reference.                            *
  195.  *                                                          *
  196.  ************************************************************
  197.  */
  198.     do
  199.       read_status = ReadPGN(annotate_in, 0);
  200.     while (read_status == 1);
  201.     if (read_status == -1)
  202.       break;
  203.     if (latex == 0) {
  204.       fprintf(annotate_out, "[Event \"%s\"]%s\n", pgn_event, html_br);
  205.       fprintf(annotate_out, "[Site \"%s\"]%s\n", pgn_site, html_br);
  206.       fprintf(annotate_out, "[Date \"%s\"]%s\n", pgn_date, html_br);
  207.       fprintf(annotate_out, "[Round \"%s\"]%s\n", pgn_round, html_br);
  208.       fprintf(annotate_out, "[White \"%s\"]%s\n", pgn_white, html_br);
  209.       fprintf(annotate_out, "[WhiteElo \"%s\"]%s\n", pgn_white_elo, html_br);
  210.       fprintf(annotate_out, "[Black \"%s\"]%s\n", pgn_black, html_br);
  211.       fprintf(annotate_out, "[BlackElo \"%s\"]%s\n", pgn_black_elo, html_br);
  212.       fprintf(annotate_out, "[Result \"%s\"]%s\n", pgn_result, html_br);
  213.       fprintf(annotate_out, "[Annotator \"Crafty v%s\"]%s\n", version,
  214.           html_br);
  215.       if (strlen(colors) != 0) {
  216.         if (!strcmp(colors, "bw") || !strcmp(colors, "wb"))
  217.           fprintf(annotate_out,
  218.               "{annotating both black and white moves.}%s\n", html_br);
  219.         else if (strchr(colors, 'b'))
  220.           fprintf(annotate_out, "{annotating only black moves.}%s\n",
  221.               html_br);
  222.         else if (strchr(colors, 'w'))
  223.           fprintf(annotate_out, "{annotating only white moves.}%s\n",
  224.               html_br);
  225.       } else
  226.         fprintf(annotate_out, "{annotating for player %s}%s\n", pname,
  227.             html_br);
  228.       fprintf(annotate_out, "{using a scoring margin of %s pawns.}%s\n",
  229.           DisplayEvaluationKibitz(annotate_margin, wtm), html_br);
  230.       fprintf(annotate_out, "{search time limit is %s}%s\n%s\n",
  231.           DisplayTimeKibitz(annotate_search_time_limit), html_br, html_br);
  232.     } else {
  233.       fprintf(annotate_out, "\\textbf{\\sc %s %s -- %s %s}%s\n", pgn_white,
  234.           pgn_white_elo, pgn_black, pgn_black_elo, html_br);
  235.       fprintf(annotate_out, "{\\em %s, %s}%s\n", pgn_site, pgn_date, html_br);
  236.       fprintf(annotate_out, "{\\small %s, Round: %s}%s\n", pgn_event,
  237.           pgn_round, html_br);
  238.       fprintf(annotate_out, "\\begin{mainline}{%s}{Crafty v%s}\n", pgn_result,
  239.           version);
  240.     }
  241.     if (strlen(colors)) {
  242.       if (!strcmp(colors, "w"))
  243.         annotate_wtm = 1;
  244.       else if (!strcmp(colors, "b"))
  245.         annotate_wtm = 0;
  246.       else if (!strcmp(colors, "wb"))
  247.         annotate_wtm = 2;
  248.       else if (!strcmp(colors, "bw"))
  249.         annotate_wtm = 2;
  250.       else {
  251.         Print(4095, "invalid color specification, retry\n");
  252.         fclose(annotate_out);
  253.         return;
  254.       }
  255.     } else {
  256.       if (strstr(pgn_white, pname))
  257.         annotate_wtm = 1;
  258.       else if (strstr(pgn_black, pname))
  259.         annotate_wtm = 0;
  260.       else {
  261.         Print(4095, "Player name doesn't match any PGN name tag, retry\n");
  262.         fclose(annotate_out);
  263.         return;
  264.       }
  265.     }
  266.     do {
  267.       fflush(annotate_out);
  268.       move = ReadNextMove(tree, buffer, 0, wtm);
  269.       if (move <= 0)
  270.         break;
  271.       strcpy(text, OutputMove(tree, 0, wtm, move));
  272.       if (history_file) {
  273.         fseek(history_file, ((move_number - 1) * 2 + 1 - wtm) * 10, SEEK_SET);
  274.         fprintf(history_file, "%9s\n", text);
  275.       }
  276.       if (wtm)
  277.         Print(4095, "White(%d): %s\n", move_number, text);
  278.       else
  279.         Print(4095, "Black(%d): %s\n", move_number, text);
  280.       if (analysis_printed)
  281.         fprintf(annotate_out, "%3d.%s%8s\n", move_number,
  282.             (wtm ? "" : "     ..."), text);
  283.       else {
  284.         if (wtm)
  285.           fprintf(annotate_out, "%3d.%8s", move_number, text);
  286.         else
  287.           fprintf(annotate_out, "%8s\n", text);
  288.       }
  289.       analysis_printed = 0;
  290.       if (move_number >= line1 && move_number <= line2) {
  291.         if (annotate_wtm == 2 || annotate_wtm == wtm) {
  292.           last_pv.pathd = 0;
  293.           last_pv.pathl = 0;
  294.           thinking = 1;
  295.           RootMoveList(wtm);
  296. /*
  297.  ************************************************************
  298.  *                                                          *
  299.  *  Search the position to see if the move played is the    *
  300.  *  best move possible.  If not, then search just the move  *
  301.  *  played to get a score for it as well, so we can         *
  302.  *  determine if annotated output is appropriate.           *
  303.  *                                                          *
  304.  ************************************************************
  305.  */
  306.           search_time_limit = annotate_search_time_limit;
  307.           search_depth = temp_search_depth;
  308.           player_score = -999999;
  309.           search_player = 1;
  310.           for (searches_done = 0; searches_done < Abs(best_moves);
  311.               searches_done++) {
  312.             if (searches_done > 0) {
  313.               search_time_limit = 3 * annotate_search_time_limit;
  314.               search_depth = temp[0].pathd;
  315.             }
  316.             Print(4095, "\n              Searching all legal moves.");
  317.             Print(4095, "----------------------------------\n");
  318.             tree->status[1] = tree->status[0];
  319.             InitializeHashTables(0);
  320.             annotate_score[searches_done] = Iterate(wtm, annotate, 1);
  321.             if (tree->pv[0].path[1] == move) {
  322.               player_score = annotate_score[searches_done];
  323.               player_pv = tree->pv[0];
  324.               search_player = 0;
  325.             }
  326.             temp[searches_done] = tree->pv[0];
  327.             for (i = 0; i < n_root_moves; i++) {
  328.               if (root_moves[i].move == tree->pv[0].path[1]) {
  329.                 for (; i < n_root_moves; i++)
  330.                   root_moves[i] = root_moves[i + 1];
  331.                 n_root_moves--;
  332.                 break;
  333.               }
  334.             }
  335.             if (n_root_moves == 0 || (annotate_margin >= 0 &&
  336.                     player_score + annotate_margin >
  337.                     annotate_score[searches_done]
  338.                     && best_moves > 0)) {
  339.               if (n_root_moves == 0)
  340.                 searches_done++;
  341.               break;
  342.             }
  343.           }
  344.           if (search_player) {
  345.             Print(4095,
  346.                 "\n              Searching only the move played in game.");
  347.             Print(4095, "--------------------\n");
  348.             tree->status[1] = tree->status[0];
  349.             search_move = move;
  350.             root_moves[0].move = move;
  351.             root_moves[0].status = 0;
  352.             n_root_moves = 1;
  353.             search_time_limit = 3 * annotate_search_time_limit;
  354.             search_depth = temp[0].pathd;
  355.             if (search_depth == temp_search_depth)
  356.               search_time_limit = annotate_search_time_limit;
  357.             InitializeHashTables(0);
  358.             player_score = Iterate(wtm, annotate, 1);
  359.             player_pv = tree->pv[0];
  360.             search_depth = temp_search_depth;
  361.             search_time_limit = annotate_search_time_limit;
  362.             search_move = 0;
  363.           }
  364. /*
  365.  ************************************************************
  366.  *                                                          *
  367.  *  Output the score/pv for the move played unless it       *
  368.  *  matches what Crafty would have played.  If it doesn't   *
  369.  *  then output the pv for what Crafty thinks is best.      *
  370.  *                                                          *
  371.  ************************************************************
  372.  */
  373.           thinking = 0;
  374.           if (player_pv.pathd > 1 && player_pv.pathl >= 1 &&
  375.               player_score + annotate_margin < annotate_score[0]
  376.               && (temp[0].path[1] != player_pv.path[1]
  377.                   || annotate_margin < 0 || best_moves != 1)) {
  378.             if (wtm) {
  379.               analysis_printed = 1;
  380.               fprintf(annotate_out, "%s\n", html_br);
  381.             }
  382.             if (html_mode == 1)
  383.               AnnotatePositionHTML(tree, wtm, annotate_out);
  384.             if (latex == 1) {
  385.               AnnotatePositionTeX(tree, wtm, annotate_out);
  386.               fprintf(annotate_out, "   \\begin{variation}\\{%d:%s\\}",
  387.                   player_pv.pathd, DisplayEvaluationKibitz(player_score,
  388.                       wtm));
  389.             } else
  390.               fprintf(annotate_out, "                ({%d:%s}",
  391.                   player_pv.pathd, DisplayEvaluationKibitz(player_score,
  392.                       wtm));
  393.             path_len = player_pv.pathl;
  394.             fprintf(annotate_out, " %s", FormatPV(tree, wtm, player_pv));
  395.             if (latex == 1)
  396.               fprintf(annotate_out, " %s\n   \\end{variation}\n",
  397.                   AnnotateVtoNAG(player_score, wtm, html_mode, latex));
  398.             else
  399.               fprintf(annotate_out, " %s)%s\n", AnnotateVtoNAG(player_score,
  400.                       wtm, html_mode, latex), html_br);
  401.             for (move_num = 0; move_num < searches_done; move_num++) {
  402.               if (move != temp[move_num].path[1]) {
  403.                 if (latex == 1)
  404.                   fprintf(annotate_out, "   \\begin{variation}\\{%d:%s\\}",
  405.                       temp[move_num].pathd,
  406.                       DisplayEvaluationKibitz(annotate_score[move_num], wtm));
  407.                 else
  408.                   fprintf(annotate_out, "                ({%d:%s}",
  409.                       temp[move_num].pathd,
  410.                       DisplayEvaluationKibitz(annotate_score[move_num], wtm));
  411.                 path_len = temp[move_num].pathl;
  412.                 fprintf(annotate_out, " %s", FormatPV(tree, wtm,
  413.                         temp[move_num]));
  414.                 if (latex == 1)
  415.                   fprintf(annotate_out, " %s\n   \\end{variation}\n",
  416.                       AnnotateVtoNAG(annotate_score[move_num], wtm, html_mode,
  417.                           latex));
  418.                 else
  419.                   fprintf(annotate_out, " %s)%s\n",
  420.                       AnnotateVtoNAG(annotate_score[move_num], wtm, html_mode,
  421.                           latex), html_br);
  422.               }
  423.             }
  424.             if (html_mode == 1)
  425.               fprintf(annotate_out, "<br>\n");
  426.             if (line2 < 0)
  427.               line2--;
  428.           }
  429.         }
  430.       }
  431. /*
  432.  ************************************************************
  433.  *                                                          *
  434.  *  Before going on to the next move, see if the user has   *
  435.  *  included a set of other moves that require a search.    *
  436.  *  If so, search them one at a time and produce the ana-   *
  437.  *  lysis for each one.                                     *
  438.  *                                                          *
  439.  ************************************************************
  440.  */
  441.       read_status = ReadPGN(annotate_in, 1);
  442.       while (read_status == 2) {
  443.         suggested = InputMove(tree, 0, wtm, 1, 0, buffer);
  444.         if (suggested > 0) {
  445.           thinking = 1;
  446.           Print(4095, "\n              Searching only the move suggested.");
  447.           Print(4095, "--------------------\n");
  448.           tree->status[1] = tree->status[0];
  449.           search_move = suggested;
  450.           search_time_limit = 3 * annotate_search_time_limit;
  451.           search_depth = temp[0].pathd;
  452.           InitializeHashTables(0);
  453.           annotate_score[0] = Iterate(wtm, annotate, 0);
  454.           search_depth = temp_search_depth;
  455.           search_time_limit = annotate_search_time_limit;
  456.           search_move = 0;
  457.           thinking = 0;
  458.           twtm = wtm;
  459.           path_len = tree->pv[0].pathl;
  460.           if (tree->pv[0].pathd > 1 && path_len >= 1) {
  461.             if (wtm && !analysis_printed) {
  462.               analysis_printed = 1;
  463.               fprintf(annotate_out, "%s\n", html_br);
  464.             }
  465.             fprintf(annotate_out, "                ({suggested %d:%s}",
  466.                 tree->pv[0].pathd, DisplayEvaluationKibitz(annotate_score[0],
  467.                     wtm));
  468.             for (i = 1; i <= path_len; i++) {
  469.               fprintf(annotate_out, " %s", OutputMove(tree, i, twtm,
  470.                       tree->pv[0].path[i]));
  471.               MakeMove(tree, i, twtm, tree->pv[0].path[i]);
  472.               twtm = Flip(twtm);
  473.             }
  474.             for (i = path_len; i > 0; i--) {
  475.               twtm = Flip(twtm);
  476.               UnmakeMove(tree, i, twtm, tree->pv[0].path[i]);
  477.             }
  478.             fprintf(annotate_out, " %s)%s\n",
  479.                 AnnotateVtoNAG(annotate_score[0], wtm, html_mode, latex),
  480.                 html_br);
  481.           }
  482.         }
  483.         read_status = ReadPGN(annotate_in, 1);
  484.         if (read_status != 2)
  485.           break;
  486.       }
  487.       if ((analysis_printed) && (latex == 0))
  488.         fprintf(annotate_out, "%s\n", html_br);
  489.       MakeMoveRoot(tree, wtm, move);
  490.       wtm = Flip(wtm);
  491.       if (wtm)
  492.         move_number++;
  493.       if (read_status != 0)
  494.         break;
  495.       if (line2 < -1)
  496.         break;
  497.     } while (1);
  498.     fprintf(annotate_out, "  %s %s\n\n", pgn_result, html_br);
  499.     if (html_mode == 1) {
  500.       fprintf(annotate_out, "%s\n", html_br);
  501.       AnnotateFooterHTML(annotate_out);
  502.     }
  503.     if (latex == 1) {
  504.       AnnotatePositionTeX(tree, wtm, annotate_out);
  505.       fprintf(annotate_out, "\\end{mainline}\n");
  506.       if (strlen(colors) != 0) {
  507.         fprintf(annotate_out, "\\begin{flushright}{\\small ");
  508.         if (!strcmp(colors, "bw") || !strcmp(colors, "wb"))
  509.           fprintf(annotate_out, "annotating both black and white moves.%s\n",
  510.               html_br);
  511.         else if (strchr(colors, 'b'))
  512.           fprintf(annotate_out, "annotating only black moves.%s\n", html_br);
  513.         else if (strchr(colors, 'w'))
  514.           fprintf(annotate_out, "annotating only white moves.%s\n", html_br);
  515.       } else
  516.         fprintf(annotate_out, "annotating for player %s%s\n", pname, html_br);
  517.       fprintf(annotate_out, "using a scoring margin of %s pawns.%s\n",
  518.           DisplayEvaluationKibitz(annotate_margin, wtm), html_br);
  519.       fprintf(annotate_out, "search time limit is %s%s\n",
  520.           DisplayTimeKibitz(annotate_search_time_limit), html_br);
  521.       fprintf(annotate_out, " } \\end{flushright}");
  522.       AnnotateFooterTeX(annotate_out);
  523.     }
  524.   }
  525.   if (annotate_out)
  526.     fclose(annotate_out);
  527.   if (annotate_in)
  528.     fclose(annotate_in);
  529.   search_time_limit = 0;
  530.   annotate_mode = 0;
  531.   swindle_mode = save_swindle_mode;
  532. }
  533.  
  534. /*
  535.  *******************************************************************************
  536.  *                                                                             *
  537.  *   These functions provide HTML output support interfaces.                   *
  538.  *                                                                             *
  539.  *******************************************************************************
  540.  */
  541. void AnnotateHeaderHTML(char *title_text, FILE * annotate_out) {
  542.   fprintf(annotate_out,
  543.       "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\"\n");
  544.   fprintf(annotate_out,
  545.       "          \"http://www.w3.org/TR/REC-html40/loose.dtd\">\n");
  546.   fprintf(annotate_out, "<HTML>\n");
  547.   fprintf(annotate_out, "<HEAD><TITLE>%s</TITLE>\n", title_text);
  548.   fprintf(annotate_out,
  549.       "<LINK rev=\"made\" href=\"hyatt@cis.uab.edu\"></HEAD>\n");
  550.   fprintf(annotate_out,
  551.       "<BODY BGColor=\"#ffffff\" text=\"#000000\" link=\"#0000ee\""
  552.       " vlink=\"#551a8b\">\n");
  553. }
  554.  
  555. void AnnotateFooterHTML(FILE * annotate_out) {
  556.   fprintf(annotate_out, "</BODY>\n");
  557.   fprintf(annotate_out, "</HTML>\n");
  558. }
  559. void AnnotatePositionHTML(TREE * RESTRICT tree, int wtm, FILE * annotate_out) {
  560.   char filename[32], html_piece;
  561.   char alt[32];
  562.   int rank, file;
  563.  
  564. /*  Display the board in HTML using table of images.          */
  565.   fprintf(annotate_out, "<br>\n");
  566.   fprintf(annotate_out, "<TABLE Border=1 CellSpacing=0 CellPadding=0>\n\n");
  567.   for (rank = RANK8; rank >= RANK1; rank--) {
  568.     fprintf(annotate_out, "<TR>\n");
  569.     for (file = FILEA; file <= FILEH; file++) {
  570.       strcpy(filename, "bitmaps/");
  571.       if ((rank + file) % 2)
  572.         strcat(filename, "w");
  573.       else
  574.         strcat(filename, "b");
  575.       html_piece = translate[PcOnSq((rank << 3) + file) + 6];
  576.       switch (html_piece) {
  577.         case 'p':
  578.           strcat(filename, "bp");
  579.           strcpy(alt, "*P");
  580.           break;
  581.         case 'r':
  582.           strcat(filename, "br");
  583.           strcpy(alt, "*R");
  584.           break;
  585.         case 'n':
  586.           strcat(filename, "bn");
  587.           strcpy(alt, "*N");
  588.           break;
  589.         case 'b':
  590.           strcat(filename, "bb");
  591.           strcpy(alt, "*B");
  592.           break;
  593.         case 'q':
  594.           strcat(filename, "bq");
  595.           strcpy(alt, "*Q");
  596.           break;
  597.         case 'k':
  598.           strcat(filename, "bk");
  599.           strcpy(alt, "*K");
  600.           break;
  601.         case 'P':
  602.           strcat(filename, "wp");
  603.           strcpy(alt, "P");
  604.           break;
  605.         case 'R':
  606.           strcat(filename, "wr");
  607.           strcpy(alt, "R");
  608.           break;
  609.         case 'N':
  610.           strcat(filename, "wn");
  611.           strcpy(alt, "N");
  612.           break;
  613.         case 'B':
  614.           strcat(filename, "wb");
  615.           strcpy(alt, "B");
  616.           break;
  617.         case 'Q':
  618.           strcat(filename, "wq");
  619.           strcpy(alt, "Q");
  620.           break;
  621.         case 'K':
  622.           strcat(filename, "wk");
  623.           strcpy(alt, "K");
  624.           break;
  625.         default:
  626.           strcat(filename, "sq");
  627.           strcpy(alt, " ");
  628.           break;
  629.       }
  630.       strcat(filename, ".gif");
  631.       fprintf(annotate_out, "<TD><IMG ALT=\"%s\" SRC=\"%s\"></TD>\n", alt,
  632.           filename);
  633.     }
  634.     fprintf(annotate_out, "</TR>\n\n");
  635.   }
  636.   fprintf(annotate_out, "</TABLE>\n");
  637.   if (wtm)
  638.     fprintf(annotate_out, "<H2>White to move.</H2>\n");
  639.   else
  640.     fprintf(annotate_out, "<H2>Black to move.</H2>\n");
  641.   fprintf(annotate_out, "<BR>\n");
  642. }
  643.  
  644. /*
  645.  *******************************************************************************
  646.  * Author         : Alexander Wagner                                           *
  647.  *                  University of Michigan                                     *
  648.  * Date           : 03.01.04                                                   *
  649.  *                                                                             *
  650.  * Last Modified  : 03.01.04                                                   *
  651.  *                                                                             *
  652.  * Based upon the HTML-Code above                                              *
  653.  *                                                                             *
  654.  * These functions provide LaTeX output capability to Crafty.                  *
  655.  *                                                                             *
  656.  *******************************************************************************
  657.  */
  658. void AnnotateHeaderTeX(FILE * annotate_out) {
  659.   fprintf(annotate_out, "\\documentclass[12pt,twocolumn]{article}\n");
  660.   fprintf(annotate_out, "%% This is a LaTeX file generated by Crafty \n");
  661.   fprintf(annotate_out,
  662.       "%% You must have the \"chess12\" package to typeset this file.\n");
  663.   fprintf(annotate_out, "\n");
  664.   fprintf(annotate_out, "\\usepackage{times}\n");
  665.   fprintf(annotate_out, "\\usepackage{a4wide}\n");
  666.   fprintf(annotate_out, "\\usepackage{chess}\n");
  667.   fprintf(annotate_out, "\\usepackage{bdfchess}\n");
  668.   fprintf(annotate_out, "\\usepackage[T1]{fontenc}\n");
  669.   fprintf(annotate_out, "\n");
  670.   fprintf(annotate_out, "\\setlength{\\columnsep}{7mm}\n");
  671.   fprintf(annotate_out, "\\setlength{\\parindent}{0pt}\n");
  672.   fprintf(annotate_out, "\n");
  673.   fprintf(annotate_out, "%% Macros for variations and diagrams:\n");
  674.   fprintf(annotate_out,
  675.       "\\newenvironment{mainline}[2]{\\bf\\newcommand{\\result}{#1}%%\n");
  676.   fprintf(annotate_out, "\\newcommand{\\commentator}{#2}\\begin{chess}}%%\n");
  677.   fprintf(annotate_out, "{\\end{chess}\\finito{\\result}{\\commentator}}\n");
  678.   fprintf(annotate_out,
  679.       "\\newenvironment{variation}{[\\begingroup\\rm\\ignorespaces}%%\n");
  680.   fprintf(annotate_out, "{\\endgroup]\\ignorespaces\\newline}\n");
  681.   fprintf(annotate_out,
  682.       "\\newcommand{\\finito}[2]{{\\bf\\hfill#1\\hfill[#2]\\par}}\n");
  683.   fprintf(annotate_out, "\\setlength{\\parindent}{0pt}\n");
  684.   fprintf(annotate_out,
  685.       "\\newenvironment{diagram}{\\begin{nochess}}"
  686.       "{$$\\showboard$$\\end{nochess}}\n");
  687.   fprintf(annotate_out, "\n\n\\begin{document}\n\n");
  688. }
  689.  
  690. void AnnotateFooterTeX(FILE * annotate_out) {
  691.   fprintf(annotate_out, "\n\n\\end{document}\n");
  692. }
  693. void AnnotatePositionTeX(TREE * tree, int wtm, FILE * annotate_out) {
  694.   char filename[32], html_piece;
  695.   int rank, file;
  696.  
  697. /*  Display the board in LaTeX using picture notation, similar to html */
  698.   fprintf(annotate_out, "\\begin{diagram}\n\\board\n");
  699.   for (rank = RANK8; rank >= RANK1; rank--) {
  700.     fprintf(annotate_out, "   {");
  701.     for (file = FILEA; file <= FILEH; file++) {
  702.       if ((rank + file) % 2)
  703.         strcpy(filename, " ");
  704.       else
  705.         strcpy(filename, "*");
  706.       html_piece = translate[PcOnSq((rank << 3) + file) + 6];
  707.       switch (html_piece) {
  708.         case 'p':
  709.           strcpy(filename, "p");
  710.           break;
  711.         case 'r':
  712.           strcpy(filename, "r");
  713.           break;
  714.         case 'n':
  715.           strcpy(filename, "n");
  716.           break;
  717.         case 'b':
  718.           strcpy(filename, "b");
  719.           break;
  720.         case 'q':
  721.           strcpy(filename, "q");
  722.           break;
  723.         case 'k':
  724.           strcpy(filename, "k");
  725.           break;
  726.         case 'P':
  727.           strcpy(filename, "P");
  728.           break;
  729.         case 'R':
  730.           strcpy(filename, "R");
  731.           break;
  732.         case 'N':
  733.           strcpy(filename, "N");
  734.           break;
  735.         case 'B':
  736.           strcpy(filename, "B");
  737.           break;
  738.         case 'Q':
  739.           strcpy(filename, "Q");
  740.           break;
  741.         case 'K':
  742.           strcpy(filename, "K");
  743.           break;
  744.         default:
  745.           break;
  746.       }
  747.       fprintf(annotate_out, "%s", filename);
  748.     }
  749.     fprintf(annotate_out, "}\n");
  750.   }
  751.   fprintf(annotate_out, "\\end{diagram}\n");
  752.   fprintf(annotate_out, "\\begin{center} \\begin{nochess}\n  {\\small ");
  753.   if (wtm)
  754.     fprintf(annotate_out, "White to move.\n");
  755.   else
  756.     fprintf(annotate_out, "Black to move.\n");
  757.   fprintf(annotate_out, "}\n \\end{nochess}\\end{center} \n\n");
  758.   fprintf(annotate_out, "\n");
  759. }
  760. char *AnnotateVtoNAG(int value, int wtm, int html_mode, int latex) {
  761.   static char buf[64];
  762.  
  763.   if (!wtm)
  764.     value = -value;
  765.   if (value > MIN_DECISIVE_ADV)
  766.     strcpy(buf, html_mode ? "+-" : "$18");
  767.   else if (value > MIN_MODERATE_ADV)
  768.     strcpy(buf, html_mode ? "+/-" : "$16");
  769.   else if (value > MIN_SLIGHT_ADV)
  770.     strcpy(buf, html_mode ? "+=" : "$14");
  771.   else if (value < -MIN_DECISIVE_ADV)
  772.     strcpy(buf, html_mode ? "-+" : "$19");
  773.   else if (value < -MIN_MODERATE_ADV)
  774.     strcpy(buf, html_mode ? "-/+" : "$17");
  775.   else if (value < -MIN_SLIGHT_ADV)
  776.     strcpy(buf, html_mode ? "=+" : "$15");
  777.   else
  778.     strcpy(buf, html_mode ? "=" : "$10");
  779.   if (latex == 1) {
  780.     if (value > MIN_DECISIVE_ADV)
  781.       strcpy(buf, "\\wdecisive");
  782.     else if (value > MIN_MODERATE_ADV)
  783.       strcpy(buf, "\\wupperhand");
  784.     else if (value > MIN_SLIGHT_ADV)
  785.       strcpy(buf, "\\wbetter");
  786.     else if (value < -MIN_DECISIVE_ADV)
  787.       strcpy(buf, "\\bdecisive");
  788.     else if (value < -MIN_MODERATE_ADV)
  789.       strcpy(buf, "\\bupperhand");
  790.     else if (value < -MIN_SLIGHT_ADV)
  791.       strcpy(buf, "\\bbetter");
  792.     else
  793.       strcpy(buf, "\\equal");
  794.   }
  795.   return buf;
  796. }
  797.