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
Annotate()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 = atof(args[4]) * PieceValues(white, pawn);
153   annotate_search_time_limit = atof(args[5]) * 100;
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     while (FOREVER) {
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     }
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  */
AnnotateHeaderHTML(char * title_text,FILE * annotate_out)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 
AnnotateFooterHTML(FILE * annotate_out)555 void AnnotateFooterHTML(FILE * annotate_out) {
556   fprintf(annotate_out, "</BODY>\n");
557   fprintf(annotate_out, "</HTML>\n");
558 }
AnnotatePositionHTML(TREE * RESTRICT tree,int wtm,FILE * annotate_out)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  */
AnnotateHeaderTeX(FILE * annotate_out)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 
AnnotateFooterTeX(FILE * annotate_out)690 void AnnotateFooterTeX(FILE * annotate_out) {
691   fprintf(annotate_out, "\n\n\\end{document}\n");
692 }
AnnotatePositionTeX(TREE * tree,int wtm,FILE * annotate_out)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 }
AnnotateVtoNAG(int value,int wtm,int html_mode,int latex)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