Rev 154 | Details | Compare with Previous | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 33 | pmbaty | 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 | * * |
||
| 108 | pmbaty | 30 | * annotate filename b|w|bw|name moves margin time [n] * |
| 33 | pmbaty | 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 | * * |
||
| 108 | pmbaty | 35 | * annotateh filename b|w|bw|name moves margin time [n] * |
| 33 | pmbaty | 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 | * * |
||
| 108 | pmbaty | 41 | * annotatet filename b|w|bw|name moves margin time [n] * |
| 33 | pmbaty | 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); |
||
| 108 | pmbaty | 110 | nargs = ReadParse(tbuffer, args, " \t;"); |
| 33 | pmbaty | 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 | } |
||
| 108 | pmbaty | 121 | nargs = ReadParse(tbuffer, args, " \t;"); |
| 33 | pmbaty | 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 | } |
||
| 156 | pmbaty | 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 |
||
| 33 | pmbaty | 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 | } |
||
| 154 | pmbaty | 266 | while (FOREVER) { |
| 33 | pmbaty | 267 | fflush(annotate_out); |
| 268 | move = ReadNextMove(tree, buffer, 0, wtm); |
||
| 269 | if (move <= 0) |
||
| 270 | break; |
||
| 108 | pmbaty | 271 | strcpy(text, OutputMove(tree, 0, wtm, move)); |
| 33 | pmbaty | 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]; |
||
| 108 | pmbaty | 319 | InitializeHashTables(0); |
| 33 | pmbaty | 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; |
||
| 108 | pmbaty | 357 | InitializeHashTables(0); |
| 33 | pmbaty | 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) { |
||
| 108 | pmbaty | 443 | suggested = InputMove(tree, 0, wtm, 1, 0, buffer); |
| 33 | pmbaty | 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; |
||
| 108 | pmbaty | 452 | InitializeHashTables(0); |
| 33 | pmbaty | 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++) { |
||
| 108 | pmbaty | 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]); |
||
| 33 | pmbaty | 472 | twtm = Flip(twtm); |
| 473 | } |
||
| 474 | for (i = path_len; i > 0; i--) { |
||
| 475 | twtm = Flip(twtm); |
||
| 108 | pmbaty | 476 | UnmakeMove(tree, i, twtm, tree->pv[0].path[i]); |
| 33 | pmbaty | 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); |
||
| 108 | pmbaty | 489 | MakeMoveRoot(tree, wtm, move); |
| 33 | pmbaty | 490 | wtm = Flip(wtm); |
| 491 | if (wtm) |
||
| 492 | move_number++; |
||
| 493 | if (read_status != 0) |
||
| 494 | break; |
||
| 495 | if (line2 < -1) |
||
| 496 | break; |
||
| 154 | pmbaty | 497 | } |
| 108 | pmbaty | 498 | fprintf(annotate_out, " %s %s\n\n", pgn_result, html_br); |
| 33 | pmbaty | 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++) { |
||
| 108 | pmbaty | 570 | strcpy(filename, "bitmaps/"); |
| 33 | pmbaty | 571 | if ((rank + file) % 2) |
| 108 | pmbaty | 572 | strcat(filename, "w"); |
| 33 | pmbaty | 573 | else |
| 108 | pmbaty | 574 | strcat(filename, "b"); |
| 33 | pmbaty | 575 | html_piece = translate[PcOnSq((rank << 3) + file) + 6]; |
| 576 | switch (html_piece) { |
||
| 577 | case 'p': |
||
| 108 | pmbaty | 578 | strcat(filename, "bp"); |
| 579 | strcpy(alt, "*P"); |
||
| 33 | pmbaty | 580 | break; |
| 581 | case 'r': |
||
| 108 | pmbaty | 582 | strcat(filename, "br"); |
| 583 | strcpy(alt, "*R"); |
||
| 33 | pmbaty | 584 | break; |
| 585 | case 'n': |
||
| 108 | pmbaty | 586 | strcat(filename, "bn"); |
| 587 | strcpy(alt, "*N"); |
||
| 33 | pmbaty | 588 | break; |
| 589 | case 'b': |
||
| 108 | pmbaty | 590 | strcat(filename, "bb"); |
| 591 | strcpy(alt, "*B"); |
||
| 33 | pmbaty | 592 | break; |
| 593 | case 'q': |
||
| 108 | pmbaty | 594 | strcat(filename, "bq"); |
| 595 | strcpy(alt, "*Q"); |
||
| 33 | pmbaty | 596 | break; |
| 597 | case 'k': |
||
| 108 | pmbaty | 598 | strcat(filename, "bk"); |
| 599 | strcpy(alt, "*K"); |
||
| 33 | pmbaty | 600 | break; |
| 601 | case 'P': |
||
| 108 | pmbaty | 602 | strcat(filename, "wp"); |
| 603 | strcpy(alt, "P"); |
||
| 33 | pmbaty | 604 | break; |
| 605 | case 'R': |
||
| 108 | pmbaty | 606 | strcat(filename, "wr"); |
| 607 | strcpy(alt, "R"); |
||
| 33 | pmbaty | 608 | break; |
| 609 | case 'N': |
||
| 108 | pmbaty | 610 | strcat(filename, "wn"); |
| 611 | strcpy(alt, "N"); |
||
| 33 | pmbaty | 612 | break; |
| 613 | case 'B': |
||
| 108 | pmbaty | 614 | strcat(filename, "wb"); |
| 615 | strcpy(alt, "B"); |
||
| 33 | pmbaty | 616 | break; |
| 617 | case 'Q': |
||
| 108 | pmbaty | 618 | strcat(filename, "wq"); |
| 619 | strcpy(alt, "Q"); |
||
| 33 | pmbaty | 620 | break; |
| 621 | case 'K': |
||
| 108 | pmbaty | 622 | strcat(filename, "wk"); |
| 623 | strcpy(alt, "K"); |
||
| 33 | pmbaty | 624 | break; |
| 625 | default: |
||
| 108 | pmbaty | 626 | strcat(filename, "sq"); |
| 627 | strcpy(alt, " "); |
||
| 33 | pmbaty | 628 | break; |
| 629 | } |
||
| 108 | pmbaty | 630 | strcat(filename, ".gif"); |
| 33 | pmbaty | 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 * |
||
| 108 | pmbaty | 647 | * University of Michigan * |
| 33 | pmbaty | 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) |
||
| 108 | pmbaty | 703 | strcpy(filename, " "); |
| 33 | pmbaty | 704 | else |
| 108 | pmbaty | 705 | strcpy(filename, "*"); |
| 33 | pmbaty | 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 | } |