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