Dave Chapman | bc6c62b | 2007-08-19 18:24:17 +0000 | [diff] [blame] | 1 | /*************************************************************************** |
| 2 | * __________ __ ___. |
| 3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| 4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| 5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| 7 | * \/ \/ \/ \/ \/ |
| 8 | * $Id$ |
| 9 | * |
| 10 | * Copyright (C) 2007 Mauricio Peccorini |
| 11 | * |
Daniel Stenberg | 2acc0ac | 2008-06-28 18:10:04 +0000 | [diff] [blame^] | 12 | * This program is free software; you can redistribute it and/or |
| 13 | * modify it under the terms of the GNU General Public License |
| 14 | * as published by the Free Software Foundation; either version 2 |
| 15 | * of the License, or (at your option) any later version. |
Dave Chapman | bc6c62b | 2007-08-19 18:24:17 +0000 | [diff] [blame] | 16 | * |
| 17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| 18 | * KIND, either express or implied. |
| 19 | * |
| 20 | ****************************************************************************/ |
| 21 | |
Dave Chapman | bc6c62b | 2007-08-19 18:24:17 +0000 | [diff] [blame] | 22 | #include "plugin.h" |
Jens Arnold | 106ac75 | 2008-03-22 14:20:04 +0000 | [diff] [blame] | 23 | #include "chessbox_pgn.h" |
Dave Chapman | bc6c62b | 2007-08-19 18:24:17 +0000 | [diff] [blame] | 24 | |
Nils Wallménius | 5ccf180 | 2007-09-02 10:11:46 +0000 | [diff] [blame] | 25 | #define PGN_FILE PLUGIN_GAMES_DIR "/chessbox.pgn" |
| 26 | #define LOG_FILE PLUGIN_GAMES_DIR "/chessbox.log" |
Dave Chapman | bc6c62b | 2007-08-19 18:24:17 +0000 | [diff] [blame] | 27 | int loghandler; |
| 28 | |
Steve Bavin | 6526577 | 2008-05-13 09:57:56 +0000 | [diff] [blame] | 29 | const struct plugin_api* rb; |
Dave Chapman | bc6c62b | 2007-08-19 18:24:17 +0000 | [diff] [blame] | 30 | |
| 31 | short kn_offs[8][2] = {{2,1},{2,-1},{-2,1},{-2,-1},{1,2},{1,-2},{-1,2},{-1,-2}}; |
| 32 | short rk_offs[4][2] = {{1,0},{-1,0},{0,1},{0,-1}}; |
| 33 | short bp_offs[4][2] = {{1,1},{-1,1},{1,-1},{-1,-1}}; |
| 34 | |
| 35 | /* global vars for pl_malloc() */ |
| 36 | void *bufptr = NULL; |
| 37 | ssize_t bufleft; |
| 38 | |
| 39 | /* simple function to "allocate" memory in pluginbuffer. |
| 40 | * (borrowed from dict.c) |
| 41 | */ |
| 42 | void *pl_malloc(ssize_t size) |
| 43 | { |
| 44 | void *ptr; |
| 45 | ptr = bufptr; |
| 46 | |
| 47 | if (bufleft < size) |
| 48 | { |
| 49 | return NULL; |
| 50 | } |
| 51 | else |
| 52 | { |
| 53 | bufptr += size; |
| 54 | return ptr; |
| 55 | } |
| 56 | } |
| 57 | |
| 58 | /* init function for pl_malloc() */ |
| 59 | void pl_malloc_init(void) |
| 60 | { |
| 61 | bufptr = rb->plugin_get_buffer((size_t *)&bufleft); |
| 62 | } |
| 63 | |
| 64 | void process_tag(struct pgn_game_node* game, char* buffer){ |
| 65 | char tag_type[20]; |
| 66 | char tag_value[255]; |
| 67 | short pos=0, pos2=0; |
| 68 | while (buffer[pos+1] != ' '){ |
| 69 | tag_type[pos] = buffer[pos+1]; |
| 70 | pos++; |
| 71 | } |
| 72 | tag_type[pos] = '\0'; |
| 73 | pos+=3; |
| 74 | while (buffer[pos] != '"'){ |
| 75 | tag_value[pos2] = buffer[pos]; |
| 76 | pos++; pos2++; |
| 77 | } |
| 78 | |
| 79 | /* truncate tag values that are too large */ |
| 80 | if (pos2 > 19){ |
| 81 | pos2 = 19; |
| 82 | } |
| 83 | tag_value[pos2] = '\0'; |
| 84 | |
| 85 | if (rb->strcmp(tag_type,"White") == 0){ |
| 86 | rb->strcpy(game->white_player, tag_value); |
| 87 | } |
| 88 | if (rb->strcmp(tag_type,"Black") == 0){ |
| 89 | rb->strcpy(game->black_player, tag_value); |
| 90 | } |
| 91 | if (rb->strcmp(tag_type,"Result") == 0){ |
| 92 | rb->strcpy(game->result, tag_value); |
| 93 | } |
| 94 | if (rb->strcmp(tag_type,"Date") == 0){ |
| 95 | rb->strcpy(game->game_date, tag_value); |
| 96 | } |
| 97 | } |
| 98 | |
| 99 | unsigned short get_next_token(const char* line_buffer, unsigned short initial_pos, |
| 100 | char* token_buffer){ |
| 101 | unsigned short pos, token_pos=0; |
| 102 | for (pos = initial_pos;line_buffer[pos] == ' ' || line_buffer[pos] == '.';pos++); |
| 103 | do { |
| 104 | token_buffer[token_pos] = line_buffer[pos]; |
| 105 | pos++; token_pos++; |
| 106 | } while (line_buffer[pos] != ' ' && line_buffer[pos] != '.' |
| 107 | && line_buffer[pos] != '\0'); |
| 108 | /* ignore annotations */ |
| 109 | while (token_buffer[token_pos-1] == '!' || token_buffer[token_pos-1] == '?'){ |
| 110 | token_pos--; |
| 111 | } |
| 112 | token_buffer[token_pos] = '\0'; |
| 113 | return pos; |
| 114 | } |
| 115 | |
| 116 | unsigned short piece_from_pgn(char pgn_piece){ |
| 117 | switch (pgn_piece){ |
| 118 | case 'R': |
| 119 | return rook; |
| 120 | case 'N': |
| 121 | return knight; |
| 122 | case 'B': |
| 123 | return bishop; |
| 124 | case 'Q': |
| 125 | return queen; |
| 126 | case 'K': |
| 127 | return king; |
| 128 | } |
| 129 | return no_piece; |
| 130 | } |
| 131 | |
| 132 | char pgn_from_piece(unsigned short piece, unsigned short color){ |
| 133 | char pgn_piece = ' '; |
| 134 | switch (piece){ |
| 135 | case pawn: |
| 136 | pgn_piece = 'P'; |
| 137 | break; |
| 138 | case rook: |
| 139 | pgn_piece = 'R'; |
| 140 | break; |
| 141 | case knight: |
| 142 | pgn_piece = 'N'; |
| 143 | break; |
| 144 | case bishop: |
| 145 | pgn_piece = 'B'; |
| 146 | break; |
| 147 | case queen: |
| 148 | pgn_piece = 'Q'; |
| 149 | break; |
| 150 | case king: |
| 151 | pgn_piece = 'K'; |
| 152 | break; |
| 153 | case no_piece: |
| 154 | pgn_piece = ' '; |
| 155 | break; |
| 156 | } |
| 157 | if (color == black && pgn_piece != ' '){ |
| 158 | pgn_piece += 32; |
| 159 | } |
| 160 | return pgn_piece; |
| 161 | } |
| 162 | |
| 163 | void pgn_to_coords(struct pgn_ply_node* ply){ |
| 164 | unsigned short str_length = rb->strlen(ply->pgn_text); |
| 165 | char str[10]; |
| 166 | rb->strcpy(str,ply->pgn_text); |
| 167 | ply->column_from = 0xFF; |
| 168 | ply->row_from = 0xFF; |
| 169 | ply->column_to = 0xFF; |
| 170 | ply->row_to = 0xFF; |
| 171 | ply->taken_piece = no_piece; |
| 172 | ply->promotion_piece = no_piece; |
| 173 | ply->enpassant = false; |
| 174 | ply->castle = false; |
| 175 | ply->promotion = false; |
| 176 | unsigned short i, j, piece; |
| 177 | bool found = false; |
| 178 | |
| 179 | if (str_length >= 3 && (str[0] == 'O' || str[0] == '0') && str[1] == '-' |
| 180 | && (str[2] == 'O' || str[2] == '0')) { |
| 181 | /* castling */ |
| 182 | ply->castle = true; |
| 183 | if (str_length >= 5 && str[3] == '-' && (str[4] == 'O' || str[4] == '0')){ |
| 184 | /* castle queenside */ |
| 185 | if (ply->player == white){ |
| 186 | ply->row_from = 0; ply->column_from = 4; |
| 187 | ply->row_to = 0; ply->column_to = 2; |
| 188 | /* update the rook's position, the king's position will be updated later */ |
| 189 | board[locn[0][3]] = rook; color[locn[0][3]] = white; |
| 190 | board[locn[0][0]] = no_piece; color[locn[0][0]] = neutral; |
| 191 | } else { |
| 192 | ply->row_from = 7; ply->column_from = 4; |
| 193 | ply->row_to = 7; ply->column_to = 2; |
| 194 | board[locn[7][3]] = rook; color[locn[7][3]] = black; |
| 195 | board[locn[7][0]] = no_piece; color[locn[7][0]] = neutral; |
| 196 | } |
| 197 | } else { |
| 198 | /* castle kingside */ |
| 199 | if (ply->player == white){ |
| 200 | ply->row_from = 0; ply->column_from = 4; |
| 201 | ply->row_to = 0; ply->column_to = 6; |
| 202 | board[locn[0][5]] = rook; color[locn[0][5]] = white; |
| 203 | board[locn[0][7]] = no_piece; color[locn[0][7]] = neutral; |
| 204 | } else { |
| 205 | ply->row_from = 7; ply->column_from = 4; |
| 206 | ply->row_to = 7; ply->column_to = 6; |
| 207 | board[locn[7][5]] = rook; color[locn[7][5]] = black; |
| 208 | board[locn[7][7]] = no_piece; color[locn[7][7]] = neutral; |
| 209 | } |
| 210 | } |
| 211 | } else if (str[0] >= 'a' && str[0] <= 'h'){ |
| 212 | /* pawns */ |
| 213 | ply->column_from = str[0] - 'a'; |
| 214 | if (str[1] == 'x'){ |
| 215 | ply->row_from = str[3] - '1' + ((ply->player==white)?-1:1); |
| 216 | ply->row_to = str[3] - '1'; |
| 217 | ply->column_to = str[2] - 'a'; |
| 218 | if (board[locn[ply->row_to][ply->column_to]] == no_piece){ |
| 219 | /* en-passant, remove the pawn */ |
| 220 | ply->enpassant = true; |
| 221 | board[locn[ply->row_from][ply->column_to]] = no_piece; |
| 222 | color[locn[ply->row_from][ply->column_to]] = neutral; |
| 223 | ply->taken_piece = pawn; |
| 224 | } else { |
| 225 | ply->taken_piece = board[locn[ply->row_to][ply->column_to]]; |
| 226 | } |
| 227 | } else { |
| 228 | ply->column_to = ply->column_from; |
| 229 | ply->row_from = str[1] - '1' + ((ply->player==white)?-1:1); |
| 230 | ply->row_to = str[1] - '1'; |
| 231 | } |
| 232 | if (board[locn[ply->row_from][ply->column_from]] == no_piece){ |
| 233 | /* the pawn moved two squares */ |
| 234 | ply->row_from += ((ply->player==white)?-1:1); |
| 235 | } |
| 236 | if (ply->row_to == 7 || ply->row_to == 0){ |
| 237 | /* promotion */ |
| 238 | if (str[2] == '='){ |
| 239 | ply->promotion_piece = piece_from_pgn(str[3]); |
| 240 | } else { |
| 241 | ply->promotion_piece = piece_from_pgn(str[5]); |
| 242 | } |
| 243 | /* change the piece in the original position and wait |
| 244 | * for the code at the end to move it |
| 245 | */ |
| 246 | board[locn[ply->row_from][ply->column_from]] = ply->promotion_piece; |
| 247 | } |
| 248 | } else { |
| 249 | /* the other pieces */ |
| 250 | piece = piece_from_pgn(str[0]); |
| 251 | if (str[2] == 'x'){ |
| 252 | /* taken a piece and move was ambiguous */ |
| 253 | ply->column_to = str[3] - 'a'; |
| 254 | ply->row_to = str[4] - '1'; |
| 255 | ply->taken_piece = board[locn[ply->row_to][ply->column_to]]; |
| 256 | if (str[1] >= 'a' && str[1] <= 'h') { |
| 257 | ply->column_from = str[1] - 'a'; |
| 258 | } else { |
| 259 | ply->row_from = str[1] - '1'; |
| 260 | } |
| 261 | } else if (str[1] == 'x') { |
| 262 | /* taken a piece */ |
| 263 | ply->column_to = str[2] - 'a'; |
| 264 | ply->row_to = str[3] - '1'; |
| 265 | ply->taken_piece = board[locn[ply->row_to][ply->column_to]]; |
| 266 | } else if (str_length >= 4 && str[3] >= '0' && str[3] <= '9'){ |
| 267 | /* no piece taken and move was ambiguous */ |
| 268 | ply->column_to = str[2] - 'a'; |
| 269 | ply->row_to = str[3] - '1'; |
| 270 | if (str[1] >= 'a' && str[1] <= 'h') { |
| 271 | ply->column_from = str[1] - 'a'; |
| 272 | } else { |
| 273 | ply->row_from = str[1] - '1'; |
| 274 | } |
| 275 | } else { |
| 276 | /* regular move */ |
| 277 | ply->column_to = str[1] - 'a'; |
| 278 | ply->row_to = str[2] - '1'; |
| 279 | } |
| 280 | if (piece == knight) { |
| 281 | for (i=0;i<8;i++){ |
| 282 | if (ply->row_to + kn_offs[i][0] >= 0 && ply->row_to + kn_offs[i][0] <= 7 |
| 283 | && ply->column_to + kn_offs[i][1] >= 0 && ply->column_to + kn_offs[i][1] <= 7 |
| 284 | && board[locn[ply->row_to + kn_offs[i][0]][ply->column_to + kn_offs[i][1]]] == knight |
| 285 | && color[locn[ply->row_to + kn_offs[i][0]][ply->column_to + kn_offs[i][1]]] == ply->player |
| 286 | && (ply->row_from == 0xFF || ply->row_from == ply->row_to + kn_offs[i][0]) |
| 287 | && (ply->column_from == 0xFF || ply->column_from == ply->column_to + kn_offs[i][1])) { |
| 288 | ply->row_from = ply->row_to + kn_offs[i][0]; |
| 289 | ply->column_from = ply->column_to + kn_offs[i][1]; |
| 290 | } |
| 291 | } |
| 292 | } |
| 293 | if (piece == rook || piece == queen || piece == king){ |
| 294 | for (i=0;i<4;i++){ |
| 295 | j = 1; |
| 296 | found = false; |
| 297 | while (ply->row_to+(j*rk_offs[i][0]) >= 0 && ply->row_to+(j*rk_offs[i][0]) <= 7 && |
| 298 | ply->column_to+(j*rk_offs[i][1]) >= 0 && ply->column_to+(j*rk_offs[i][1]) <= 7){ |
| 299 | if (board[locn[ply->row_to+(j*rk_offs[i][0])][ply->column_to+(j*rk_offs[i][1])]] != no_piece) { |
| 300 | if (board[locn[ply->row_to+(j*rk_offs[i][0])][ply->column_to+(j*rk_offs[i][1])]] == piece && |
| 301 | color[locn[ply->row_to+(j*rk_offs[i][0])][ply->column_to+(j*rk_offs[i][1])]] == ply->player && |
| 302 | (ply->row_from == 0xFF || ply->row_from == ply->row_to+(j*rk_offs[i][0])) && |
| 303 | (ply->column_from == 0xFF || ply->column_from == ply->column_to+(j*rk_offs[i][1]))) { |
| 304 | ply->row_from = ply->row_to+(j*rk_offs[i][0]); |
| 305 | ply->column_from = ply->column_to+(j*rk_offs[i][1]); |
| 306 | found = true; |
| 307 | } |
| 308 | break; |
| 309 | } |
| 310 | j++; |
| 311 | } |
| 312 | if (found) { |
| 313 | break; |
| 314 | } |
| 315 | } |
| 316 | } |
| 317 | if (piece == bishop || ((piece == queen || piece == king) && !found)){ |
| 318 | for (i=0;i<4;i++){ |
| 319 | j = 1; |
| 320 | found = false; |
| 321 | while (ply->row_to+(j*bp_offs[i][0]) >= 0 && ply->row_to+(j*bp_offs[i][0]) <= 7 && |
| 322 | ply->column_to+(j*bp_offs[i][1]) >= 0 && ply->column_to+(j*bp_offs[i][1]) <= 7){ |
| 323 | if (board[locn[ply->row_to+(j*bp_offs[i][0])][ply->column_to+(j*bp_offs[i][1])]] != no_piece) { |
| 324 | if (board[locn[ply->row_to+(j*bp_offs[i][0])][ply->column_to+(j*bp_offs[i][1])]] == piece && |
| 325 | color[locn[ply->row_to+(j*bp_offs[i][0])][ply->column_to+(j*bp_offs[i][1])]] == ply->player && |
| 326 | (ply->row_from == 0xFF || ply->row_from == ply->row_to+(j*bp_offs[i][0])) && |
| 327 | (ply->column_from == 0xFF || ply->column_from == ply->column_to+(j*bp_offs[i][1]))) { |
| 328 | ply->row_from = ply->row_to+(j*bp_offs[i][0]); |
| 329 | ply->column_from = ply->column_to+(j*bp_offs[i][1]); |
| 330 | found = true; |
| 331 | } |
| 332 | break; |
| 333 | } |
| 334 | j++; |
| 335 | } |
| 336 | if (found) { |
| 337 | break; |
| 338 | } |
| 339 | } |
| 340 | } |
| 341 | } |
| 342 | |
| 343 | /* leave a very complete log of the parsing of the game while it gets stable */ |
| 344 | for (i=0;i<8;i++){ |
| 345 | for (j=0;j<8;j++) { |
| 346 | rb->fdprintf(loghandler,"%c",pgn_from_piece(board[locn[7-i][j]],color[locn[7-i][j]])); |
| 347 | } |
| 348 | rb->fdprintf(loghandler,"\n"); |
| 349 | } |
| 350 | |
| 351 | /* update the board */ |
| 352 | board[locn[ply->row_to][ply->column_to]] = board[locn[ply->row_from][ply->column_from]]; |
| 353 | color[locn[ply->row_to][ply->column_to]] = color[locn[ply->row_from][ply->column_from]]; |
| 354 | board[locn[ply->row_from][ply->column_from]] = no_piece; |
| 355 | color[locn[ply->row_from][ply->column_from]] = neutral; |
| 356 | } |
| 357 | |
Nils Wallménius | 5ccf180 | 2007-09-02 10:11:46 +0000 | [diff] [blame] | 358 | void coords_to_pgn(struct pgn_ply_node* ply){ |
| 359 | int pos = 0,i,j; |
| 360 | unsigned short moving_piece = board[locn[ply->row_from][ply->column_from]]; |
| 361 | char unambiguous_position; |
| 362 | bool found = false; |
| 363 | char alg_move[5]; |
| 364 | char move_buffer[10]; |
| 365 | short move; |
| 366 | if (moving_piece == king){ |
| 367 | /* check castling */ |
| 368 | if (ply->column_from == 4 && ply->column_to == 6){ |
| 369 | /* castling kingside */ |
| 370 | rb->strcpy(ply->pgn_text,"O-O"); |
| 371 | ply->castle = true; |
| 372 | } else if (ply->column_from == 4 && ply->column_to == 2){ |
| 373 | /* castling queenside */ |
| 374 | rb->strcpy(ply->pgn_text,"O-O-O"); |
| 375 | } else { |
| 376 | if (board[locn[ply->row_to][ply->column_to]] != no_piece){ |
| 377 | rb->snprintf(ply->pgn_text,10,"Kx%c%c",'a'+ply->column_to, |
| 378 | '1'+ply->row_to); |
| 379 | } else { |
| 380 | rb->snprintf(ply->pgn_text,10,"K%c%c",'a'+ply->column_to, |
| 381 | '1'+ply->row_to); |
| 382 | } |
| 383 | } |
| 384 | } else if (moving_piece == pawn){ |
| 385 | if (ply->column_from != ply->column_to){ |
| 386 | /* check enpassant */ |
| 387 | if (board[locn[ply->row_to][ply->column_to]] == no_piece){ |
| 388 | ply->enpassant = true; |
| 389 | } |
| 390 | /* check promotions when taking a piece */ |
| 391 | if (ply->row_to == 0 || ply->row_to == 7) { |
| 392 | ply->promotion = true; |
| 393 | ply->promotion_piece = queen; |
| 394 | rb->snprintf(ply->pgn_text,10,"%cx%c%c=D", 'a'+ply->column_from, |
| 395 | 'a'+ply->column_to,'1'+ply->row_to); |
| 396 | } else { |
| 397 | rb->snprintf(ply->pgn_text,10,"%cx%c%c", 'a'+ply->column_from, |
| 398 | 'a'+ply->column_to,'1'+ply->row_to); |
| 399 | } |
| 400 | } else { |
| 401 | /* check promotions when not taking a piece */ |
| 402 | if (ply->row_to == 0 || ply->row_to == 7) { |
| 403 | ply->promotion = true; |
| 404 | ply->promotion_piece = queen; |
| 405 | rb->snprintf(ply->pgn_text,10,"%c%c=D", 'a'+ply->column_to, |
| 406 | '1'+ply->row_to); |
| 407 | } else { |
| 408 | rb->snprintf(ply->pgn_text,10,"%c%c", 'a'+ply->column_to, |
| 409 | '1'+ply->row_to); |
| 410 | } |
| 411 | } |
| 412 | } else { |
| 413 | /* verify ambiguous moves for the different kinds of pieces */ |
| 414 | unambiguous_position = '\0'; |
| 415 | if (moving_piece == knight){ |
| 416 | for (i=0;i<8;i++){ |
| 417 | if (ply->row_to + kn_offs[i][0] >= 0 && ply->row_to + kn_offs[i][0] <= 7 |
| 418 | && ply->column_to + kn_offs[i][1] >= 0 && ply->column_to + kn_offs[i][1] <= 7 |
| 419 | && board[locn[ply->row_to + kn_offs[i][0]][ply->column_to + kn_offs[i][1]]] == knight |
| 420 | && color[locn[ply->row_to + kn_offs[i][0]][ply->column_to + kn_offs[i][1]]] == ply->player |
| 421 | && (ply->row_to + kn_offs[i][0] != ply->row_from |
| 422 | || ply->column_to + kn_offs[i][1] != ply->column_from)){ |
| 423 | if (ply->row_to + kn_offs[i][0] != ply->row_from){ |
| 424 | unambiguous_position = '1' + ply->row_from; |
| 425 | } else { |
| 426 | unambiguous_position = 'a' + ply->column_from; |
| 427 | } |
| 428 | break; |
| 429 | } |
| 430 | } |
| 431 | } |
| 432 | if (moving_piece == rook || moving_piece == queen){ |
| 433 | found = false; |
| 434 | for (i=0;i<4;i++){ |
| 435 | j=1; |
| 436 | while (ply->row_to+(j*rk_offs[i][0]) >= 0 && ply->row_to+(j*rk_offs[i][0]) <= 7 && |
| 437 | ply->column_to+(j*rk_offs[i][1]) >= 0 && ply->column_to+(j*rk_offs[i][1]) <= 7){ |
| 438 | if (board[locn[ply->row_to+(j*rk_offs[i][0])][ply->column_to+(j*rk_offs[i][1])]] != no_piece) { |
| 439 | if (board[locn[ply->row_to+(j*rk_offs[i][0])][ply->column_to+(j*rk_offs[i][1])]] == moving_piece && |
| 440 | color[locn[ply->row_to+(j*rk_offs[i][0])][ply->column_to+(j*rk_offs[i][1])]] == ply->player && |
| 441 | (ply->row_to+(j*rk_offs[i][0]) != ply->row_from |
| 442 | || ply->column_to+(j*rk_offs[i][1]) != ply->column_from)) { |
| 443 | if (ply->row_to+(j*rk_offs[i][0]) != ply->row_from){ |
| 444 | unambiguous_position = '1' + ply->row_from; |
| 445 | } else { |
| 446 | unambiguous_position = 'a' + ply->column_from; |
| 447 | } |
| 448 | found = true; |
| 449 | } |
| 450 | break; |
| 451 | } |
| 452 | j++; |
| 453 | } |
| 454 | if (found) { |
| 455 | break; |
| 456 | } |
| 457 | } |
| 458 | } |
| 459 | if (moving_piece == bishop || (moving_piece == queen && !found)){ |
| 460 | for (i=0;i<4;i++){ |
| 461 | j=1; |
| 462 | while (ply->row_to+(j*bp_offs[i][0]) >= 0 && ply->row_to+(j*bp_offs[i][0]) <= 7 && |
| 463 | ply->column_to+(j*bp_offs[i][1]) >= 0 && ply->column_to+(j*bp_offs[i][1]) <= 7){ |
| 464 | if (board[locn[ply->row_to+(j*bp_offs[i][0])][ply->column_to+(j*bp_offs[i][1])]] != no_piece) { |
| 465 | if (board[locn[ply->row_to+(j*bp_offs[i][0])][ply->column_to+(j*bp_offs[i][1])]] == moving_piece && |
| 466 | color[locn[ply->row_to+(j*bp_offs[i][0])][ply->column_to+(j*bp_offs[i][1])]] == ply->player && |
| 467 | (ply->row_to+(j*bp_offs[i][0]) != ply->row_from |
| 468 | || ply->column_to+(j*bp_offs[i][1]) != ply->column_from)) { |
| 469 | if (ply->row_to+(j*bp_offs[i][0]) != ply->row_from){ |
| 470 | unambiguous_position = '1' + ply->row_from; |
| 471 | } else { |
| 472 | unambiguous_position = 'a' + ply->column_from; |
| 473 | } |
| 474 | found = true; |
| 475 | } |
| 476 | break; |
| 477 | } |
| 478 | j++; |
| 479 | } |
| 480 | if (found) { |
| 481 | break; |
| 482 | } |
| 483 | } |
| 484 | } |
| 485 | /* generate the first portion of the PGN text |
| 486 | * always as white so all uppercase, black/white considerations |
| 487 | * will be useful for FEN notation but not in this case |
| 488 | */ |
| 489 | if (unambiguous_position == '\0'){ |
| 490 | if (board[locn[ply->row_to][ply->column_to]] != no_piece){ |
| 491 | rb->snprintf(ply->pgn_text,10,"%cx%c%c", |
| 492 | pgn_from_piece(moving_piece,white) , |
| 493 | 'a'+ply->column_to, '1'+ply->row_to); |
| 494 | } else { |
| 495 | rb->snprintf(ply->pgn_text,10,"%c%c%c", |
| 496 | pgn_from_piece(moving_piece,white) , |
| 497 | 'a'+ply->column_to, '1'+ply->row_to); |
| 498 | } |
| 499 | } else { |
| 500 | if (board[locn[ply->row_to][ply->column_to]] != no_piece){ |
| 501 | rb->snprintf(ply->pgn_text,10,"%c%cx%c%c", |
| 502 | pgn_from_piece(moving_piece,white) , |
| 503 | unambiguous_position, 'a'+ply->column_to, |
| 504 | '1'+ply->row_to); |
| 505 | } else { |
| 506 | rb->snprintf(ply->pgn_text,10,"%c%c%c%c", |
| 507 | pgn_from_piece(moving_piece,white) , |
| 508 | unambiguous_position, 'a'+ply->column_to, |
| 509 | '1'+ply->row_to); |
| 510 | } |
| 511 | } |
| 512 | } |
| 513 | /* update the board */ |
| 514 | rb->snprintf(alg_move,5,"%c%c%c%c",'a' + ply->column_from, '1' + ply->row_from, |
| 515 | 'a' + ply->column_to, '1' + ply->row_to); |
| 516 | /* The function returns false if the move is invalid, but since we're |
| 517 | * replaying the game, that should not be posible |
| 518 | */ |
| 519 | VerifyMove (ply->player, alg_move , 0 , &move, move_buffer ); |
| 520 | |
| 521 | /* add check/mate indicators */ |
| 522 | for (pos=0;ply->pgn_text[pos] != '\0';pos++); |
| 523 | if (ply->checkmate) { |
| 524 | ply->pgn_text[pos] = '#'; pos++; |
| 525 | ply->pgn_text[pos] = '\0'; pos++; |
| 526 | } else if (move_buffer[4] == '+'){ |
| 527 | ply->pgn_text[pos] = '+'; pos++; |
| 528 | ply->pgn_text[pos] = '\0'; pos++; |
| 529 | } |
| 530 | } |
| 531 | |
Nils Wallménius | 6848961 | 2008-04-09 15:25:17 +0000 | [diff] [blame] | 532 | char * get_game_text(int selected_item, void *data, |
| 533 | char *buffer, size_t buffer_len){ |
Dave Chapman | bc6c62b | 2007-08-19 18:24:17 +0000 | [diff] [blame] | 534 | int i; |
| 535 | struct pgn_game_node *temp_node = (struct pgn_game_node *)data; |
| 536 | char text_buffer[50]; |
| 537 | |
| 538 | for (i=0;i<selected_item && temp_node != NULL;i++){ |
| 539 | temp_node = temp_node->next_node; |
| 540 | } |
| 541 | if (temp_node == NULL){ |
| 542 | return NULL; |
| 543 | } |
| 544 | rb->snprintf(text_buffer, 50,"%s vs. %s (%s)", temp_node->white_player, |
| 545 | temp_node->black_player, temp_node->game_date); |
| 546 | |
Nils Wallménius | 6848961 | 2008-04-09 15:25:17 +0000 | [diff] [blame] | 547 | rb->strncpy(buffer, text_buffer, buffer_len); |
Dave Chapman | bc6c62b | 2007-08-19 18:24:17 +0000 | [diff] [blame] | 548 | return buffer; |
| 549 | } |
| 550 | |
Nils Wallménius | 5ccf180 | 2007-09-02 10:11:46 +0000 | [diff] [blame] | 551 | void write_pgn_token(int fhandler, char *buffer, size_t *line_length){ |
| 552 | if (*line_length + rb->strlen(buffer) + 1 > 80){ |
| 553 | rb->fdprintf(fhandler,"\n"); |
| 554 | *line_length = 0; |
| 555 | } |
| 556 | rb->fdprintf(fhandler,"%s ",buffer); |
| 557 | *line_length += (rb->strlen(buffer) + 1); |
| 558 | } |
| 559 | |
Dave Chapman | bc6c62b | 2007-08-19 18:24:17 +0000 | [diff] [blame] | 560 | /* ---- api functions ---- */ |
Steve Bavin | 6526577 | 2008-05-13 09:57:56 +0000 | [diff] [blame] | 561 | struct pgn_game_node* pgn_list_games(const struct plugin_api* api,const char* filename){ |
Dave Chapman | bc6c62b | 2007-08-19 18:24:17 +0000 | [diff] [blame] | 562 | int fhandler; |
| 563 | char line_buffer[128]; |
Nils Wallménius | 5ccf180 | 2007-09-02 10:11:46 +0000 | [diff] [blame] | 564 | struct pgn_game_node size_node, *first_game = NULL; |
| 565 | struct pgn_game_node *curr_node = NULL, *temp_node; |
Dave Chapman | bc6c62b | 2007-08-19 18:24:17 +0000 | [diff] [blame] | 566 | unsigned short game_count = 1; |
| 567 | int line_count = 0; |
| 568 | bool header_start = true, game_start = false; |
| 569 | rb = api; |
| 570 | |
| 571 | if ( (fhandler = rb->open(filename, O_RDONLY)) == 0 ) return NULL; |
| 572 | |
| 573 | if (bufptr == NULL){ |
| 574 | pl_malloc_init(); |
| 575 | } |
| 576 | while (rb->read_line(fhandler, line_buffer, sizeof line_buffer) > 0){ |
| 577 | line_count++; |
| 578 | /* looking for a game header */ |
| 579 | if (header_start) { |
| 580 | /* a new game header is found */ |
| 581 | if (line_buffer[0] == '['){ |
| 582 | temp_node = (struct pgn_game_node *)pl_malloc(sizeof size_node); |
| 583 | temp_node->next_node = NULL; |
| 584 | if (curr_node == NULL) { |
| 585 | first_game = curr_node = temp_node; |
| 586 | } else { |
| 587 | curr_node->next_node = temp_node; |
| 588 | curr_node = temp_node; |
| 589 | } |
| 590 | process_tag(curr_node, line_buffer); |
| 591 | curr_node->game_number = game_count; |
| 592 | curr_node->pgn_line = 0; |
| 593 | game_count++; |
| 594 | header_start = false; |
| 595 | game_start = true; |
| 596 | } |
| 597 | } else { |
| 598 | if (line_buffer[0] == '['){ |
| 599 | process_tag(curr_node, line_buffer); |
Nils Wallménius | 5ccf180 | 2007-09-02 10:11:46 +0000 | [diff] [blame] | 600 | } else if (line_buffer[0] == '\r' |
| 601 | || line_buffer[0] == '\n' |
| 602 | || line_buffer[0] == '\0'){ |
Dave Chapman | bc6c62b | 2007-08-19 18:24:17 +0000 | [diff] [blame] | 603 | if (game_start) { |
| 604 | game_start = false; |
| 605 | } else { |
| 606 | header_start = true; |
| 607 | } |
| 608 | } else { |
| 609 | if (curr_node->pgn_line == 0) { |
| 610 | curr_node->pgn_line = line_count; |
| 611 | } |
| 612 | } |
| 613 | } |
| 614 | } |
| 615 | rb->close(fhandler); |
| 616 | return first_game; |
| 617 | } |
| 618 | |
Steve Bavin | 6526577 | 2008-05-13 09:57:56 +0000 | [diff] [blame] | 619 | struct pgn_game_node* pgn_show_game_list(const struct plugin_api* api, |
Nils Wallménius | 5ccf180 | 2007-09-02 10:11:46 +0000 | [diff] [blame] | 620 | struct pgn_game_node* first_game){ |
Dave Chapman | bc6c62b | 2007-08-19 18:24:17 +0000 | [diff] [blame] | 621 | int curr_selection = 0; |
| 622 | int button; |
| 623 | struct gui_synclist games_list; |
| 624 | int i; |
| 625 | struct pgn_game_node *temp_node = first_game; |
| 626 | |
| 627 | rb=api; |
| 628 | |
| 629 | for (i=0;temp_node != NULL;i++){ |
| 630 | temp_node = temp_node->next_node; |
| 631 | } |
| 632 | |
| 633 | |
Jonathan Gordon | 5ca1539 | 2008-03-26 03:35:24 +0000 | [diff] [blame] | 634 | rb->gui_synclist_init(&games_list, &get_game_text, first_game, false, 1, NULL); |
Dave Chapman | bc6c62b | 2007-08-19 18:24:17 +0000 | [diff] [blame] | 635 | rb->gui_synclist_set_title(&games_list, "Games", NOICON); |
| 636 | rb->gui_synclist_set_icon_callback(&games_list, NULL); |
| 637 | rb->gui_synclist_set_nb_items(&games_list, i); |
| 638 | rb->gui_synclist_limit_scroll(&games_list, true); |
| 639 | rb->gui_synclist_select_item(&games_list, 0); |
| 640 | |
| 641 | while (true) { |
| 642 | rb->gui_syncstatusbar_draw(rb->statusbars, true); |
| 643 | rb->gui_synclist_draw(&games_list); |
| 644 | curr_selection = rb->gui_synclist_get_sel_pos(&games_list); |
| 645 | button = rb->get_action(CONTEXT_LIST,TIMEOUT_BLOCK); |
Jonathan Gordon | cf1cef5 | 2007-09-17 10:08:50 +0000 | [diff] [blame] | 646 | if (rb->gui_synclist_do_button(&games_list,&button,LIST_WRAP_OFF)){ |
Dave Chapman | bc6c62b | 2007-08-19 18:24:17 +0000 | [diff] [blame] | 647 | continue; |
| 648 | } |
| 649 | switch (button) { |
| 650 | case ACTION_STD_OK: |
| 651 | temp_node = first_game; |
| 652 | for (i=0;i<curr_selection && temp_node != NULL;i++){ |
| 653 | temp_node = temp_node->next_node; |
| 654 | } |
| 655 | return temp_node; |
| 656 | break; |
| 657 | case ACTION_STD_CANCEL: |
| 658 | return NULL; |
| 659 | break; |
| 660 | } |
| 661 | } |
| 662 | } |
| 663 | |
Steve Bavin | 6526577 | 2008-05-13 09:57:56 +0000 | [diff] [blame] | 664 | void pgn_parse_game(const struct plugin_api* api, const char* filename, |
Nils Wallménius | 5ccf180 | 2007-09-02 10:11:46 +0000 | [diff] [blame] | 665 | struct pgn_game_node* selected_game){ |
| 666 | struct pgn_ply_node size_ply, *first_ply = NULL; |
| 667 | struct pgn_ply_node *temp_ply = NULL, *curr_node = NULL; |
Dave Chapman | bc6c62b | 2007-08-19 18:24:17 +0000 | [diff] [blame] | 668 | int fhandler, i; |
| 669 | char line_buffer[128]; |
| 670 | char token_buffer[10]; |
| 671 | unsigned short pos; |
| 672 | unsigned short curr_player = white; |
| 673 | rb = api; |
| 674 | |
| 675 | fhandler = rb->open(filename, O_RDONLY); |
| 676 | |
| 677 | /* seek the line where the pgn of the selected game starts */ |
| 678 | for (i=1;i<selected_game->pgn_line;i++){ |
| 679 | rb->read_line(fhandler, line_buffer, sizeof line_buffer); |
| 680 | } |
| 681 | |
| 682 | loghandler = rb->open(LOG_FILE, O_WRONLY | O_CREAT); |
| 683 | |
| 684 | GNUChess_Initialize(); |
| 685 | |
| 686 | while (rb->read_line(fhandler, line_buffer, sizeof line_buffer) > 0){ |
| 687 | if (line_buffer[0] == '\r' || line_buffer[0] == '\n' || line_buffer[0] == '\0'){ |
| 688 | break; |
| 689 | } |
| 690 | pos = 0; |
| 691 | while (pos < rb->strlen(line_buffer)){ |
| 692 | pos = get_next_token(line_buffer, pos, token_buffer); |
| 693 | if ((token_buffer[0] >= 'A' && token_buffer[0] <= 'Z') |
| 694 | || (token_buffer[0] >= 'a' && token_buffer[0] <= 'z') |
| 695 | || (token_buffer[0] == '0' && token_buffer[2] != '1')){ |
| 696 | temp_ply = (struct pgn_ply_node *)pl_malloc(sizeof size_ply); |
| 697 | temp_ply->player = curr_player; |
| 698 | curr_player = (curr_player==white)?black:white; |
| 699 | rb->strcpy(temp_ply->pgn_text, token_buffer); |
| 700 | pgn_to_coords(temp_ply); |
| 701 | temp_ply->prev_node = NULL; |
| 702 | temp_ply->next_node = NULL; |
| 703 | if (first_ply == NULL) { |
| 704 | first_ply = curr_node = temp_ply; |
| 705 | } else { |
| 706 | curr_node->next_node = temp_ply; |
| 707 | temp_ply->prev_node = curr_node; |
| 708 | curr_node = temp_ply; |
| 709 | } |
Nils Wallménius | 5ccf180 | 2007-09-02 10:11:46 +0000 | [diff] [blame] | 710 | rb->fdprintf(loghandler, |
| 711 | "player: %u; pgn: %s; from: %u,%u; to: %u,%u; taken: %u.\n", |
| 712 | temp_ply->player, temp_ply->pgn_text, temp_ply->row_from, |
| 713 | temp_ply->column_from, temp_ply->row_to, |
| 714 | temp_ply->column_to, temp_ply->taken_piece); |
Dave Chapman | bc6c62b | 2007-08-19 18:24:17 +0000 | [diff] [blame] | 715 | } |
| 716 | } |
| 717 | } |
| 718 | |
| 719 | rb->close(loghandler); |
| 720 | |
Nils Wallménius | 5ccf180 | 2007-09-02 10:11:46 +0000 | [diff] [blame] | 721 | /* additional dummy ply to represent end of file without |
| 722 | *loosing the previous node's pointer |
| 723 | */ |
Dave Chapman | bc6c62b | 2007-08-19 18:24:17 +0000 | [diff] [blame] | 724 | if (first_ply != NULL){ |
| 725 | temp_ply = (struct pgn_ply_node *)pl_malloc(sizeof size_ply); |
| 726 | temp_ply->player = neutral; |
| 727 | temp_ply->prev_node = curr_node; |
| 728 | curr_node->next_node = temp_ply; |
| 729 | } |
| 730 | selected_game->first_ply = first_ply; |
| 731 | rb->close(fhandler); |
| 732 | } |
Nils Wallménius | 5ccf180 | 2007-09-02 10:11:46 +0000 | [diff] [blame] | 733 | |
Steve Bavin | 6526577 | 2008-05-13 09:57:56 +0000 | [diff] [blame] | 734 | struct pgn_game_node* pgn_init_game(const struct plugin_api* api){ |
Nils Wallménius | 5ccf180 | 2007-09-02 10:11:46 +0000 | [diff] [blame] | 735 | struct pgn_game_node game_size, *game; |
| 736 | struct pgn_ply_node ply_size, *ply; |
| 737 | struct tm *current_time; |
| 738 | |
| 739 | rb = api; |
| 740 | |
| 741 | if (bufptr == NULL){ |
| 742 | pl_malloc_init(); |
| 743 | } |
| 744 | |
| 745 | /* create an "end of game" dummy ply and assign defaults */ |
| 746 | ply = (struct pgn_ply_node *)pl_malloc(sizeof ply_size); |
| 747 | ply->player = neutral; |
| 748 | ply->pgn_text[0] = '\0'; |
| 749 | ply->prev_node = NULL; |
| 750 | ply->next_node = NULL; |
| 751 | |
| 752 | /* create the game and assign defaults */ |
| 753 | game = (struct pgn_game_node *)pl_malloc(sizeof game_size); |
| 754 | game->game_number = 0; |
| 755 | rb->strcpy(game->white_player,"Player"); |
| 756 | rb->strcpy(game->black_player,"GnuChess"); |
| 757 | current_time = rb->get_time(); |
| 758 | if (current_time->tm_year < 100){ |
| 759 | rb->snprintf(game->game_date,11,"????.??.??"); |
| 760 | } else { |
| 761 | rb->snprintf(game->game_date,11,"%4u.%2u.%2u",current_time->tm_year + 1900, |
| 762 | current_time->tm_mon + 1, current_time->tm_mday); |
| 763 | } |
| 764 | rb->strcpy(game->result,"*"); |
| 765 | game->pgn_line = 0; |
| 766 | game->first_ply = ply; |
| 767 | game->next_node = NULL; |
| 768 | |
| 769 | return game; |
| 770 | } |
| 771 | |
Steve Bavin | 6526577 | 2008-05-13 09:57:56 +0000 | [diff] [blame] | 772 | void pgn_append_ply(const struct plugin_api* api, struct pgn_game_node* game, |
Nils Wallménius | 5ccf180 | 2007-09-02 10:11:46 +0000 | [diff] [blame] | 773 | unsigned short ply_player, char *move_buffer, bool is_mate){ |
| 774 | struct pgn_ply_node ply_size, *ply, *temp; |
| 775 | |
| 776 | rb = api; |
| 777 | |
| 778 | ply = (struct pgn_ply_node *)pl_malloc(sizeof ply_size); |
| 779 | ply->player = ply_player; |
| 780 | ply->column_from = move_buffer[0] - 'a'; |
| 781 | ply->row_from = move_buffer[1] - '1'; |
| 782 | ply->column_to = move_buffer[2] - 'a'; |
| 783 | ply->row_to = move_buffer[3] - '1'; |
| 784 | ply->castle = false; |
| 785 | ply->promotion = false; |
| 786 | ply->enpassant = false; |
| 787 | ply->promotion_piece = no_piece; |
| 788 | ply->taken_piece = no_piece; |
| 789 | ply->draw = false; |
| 790 | ply->checkmate = is_mate; |
| 791 | |
| 792 | /* move the pointer to the "end of game" marker ply */ |
| 793 | for (temp=game->first_ply;temp->next_node!=NULL;temp=temp->next_node); |
| 794 | |
| 795 | /* arrange the pointers to insert the ply before the marker */ |
| 796 | ply->next_node = temp; |
| 797 | ply->prev_node = temp->prev_node; |
| 798 | if (temp->prev_node == NULL){ |
| 799 | game->first_ply = ply; |
| 800 | } else { |
| 801 | temp->prev_node->next_node = ply; |
| 802 | } |
| 803 | temp->prev_node = ply; |
| 804 | } |
| 805 | |
Steve Bavin | 6526577 | 2008-05-13 09:57:56 +0000 | [diff] [blame] | 806 | void pgn_set_result(const struct plugin_api* api, struct pgn_game_node* game, |
Nils Wallménius | 5ccf180 | 2007-09-02 10:11:46 +0000 | [diff] [blame] | 807 | bool is_mate){ |
| 808 | |
| 809 | rb = api; |
| 810 | |
| 811 | struct pgn_ply_node *ply; |
| 812 | for(ply=game->first_ply;ply->next_node != NULL;ply=ply->next_node); |
| 813 | if (is_mate){ |
| 814 | ply->prev_node->checkmate = true; |
| 815 | } else { |
| 816 | ply->prev_node->draw = true; |
| 817 | } |
| 818 | } |
| 819 | |
Steve Bavin | 6526577 | 2008-05-13 09:57:56 +0000 | [diff] [blame] | 820 | void pgn_store_game(const struct plugin_api* api, struct pgn_game_node* game){ |
Nils Wallménius | 5ccf180 | 2007-09-02 10:11:46 +0000 | [diff] [blame] | 821 | int fhandler; |
| 822 | struct pgn_ply_node *ply; |
| 823 | unsigned ply_count; |
| 824 | size_t line_length=0; |
| 825 | char buffer[10]; |
| 826 | |
| 827 | rb = api; |
| 828 | |
| 829 | GNUChess_Initialize(); |
| 830 | |
| 831 | ply_count=0; |
| 832 | ply=game->first_ply; |
| 833 | while (ply->next_node!=NULL){ |
| 834 | coords_to_pgn(ply); |
| 835 | if (ply->checkmate){ |
| 836 | if (ply->player == white){ |
| 837 | rb->strcpy(game->result,"1-0"); |
| 838 | } else { |
| 839 | rb->strcpy(game->result,"0-1"); |
| 840 | } |
| 841 | } |
| 842 | if (ply->draw){ |
| 843 | rb->strcpy(game->result,"1/2-1/2"); |
| 844 | } |
| 845 | ply=ply->next_node; |
| 846 | ply_count++; |
| 847 | } |
| 848 | |
| 849 | fhandler = rb->open(PGN_FILE, O_WRONLY|O_CREAT|O_APPEND); |
| 850 | |
| 851 | |
| 852 | /* the first 7 tags are mandatory according to the PGN specification so we |
| 853 | * have to include them even if the values don't make much sense |
| 854 | */ |
| 855 | rb->fdprintf(fhandler,"[Event \"Casual Game\"]\n"); |
| 856 | rb->fdprintf(fhandler,"[Site \"?\"]\n"); |
| 857 | rb->fdprintf(fhandler,"[Date \"%s\"]\n",game->game_date); |
| 858 | rb->fdprintf(fhandler,"[Round \"?\"]\n"); |
| 859 | rb->fdprintf(fhandler,"[White \"%s\"]\n",game->white_player); |
| 860 | rb->fdprintf(fhandler,"[Black \"%s\"]\n",game->black_player); |
| 861 | rb->fdprintf(fhandler,"[Result \"%s\"]\n",game->result); |
| 862 | rb->fdprintf(fhandler,"[PlyCount \"%u\"]\n",ply_count); |
| 863 | |
| 864 | /* leave a blank line between the tag section and the game section */ |
| 865 | rb->fdprintf(fhandler,"\n"); |
| 866 | |
| 867 | /* write the plies in several lines of up to 80 characters */ |
| 868 | for (ply_count=0, ply=game->first_ply;ply->next_node!=NULL; |
| 869 | ply=ply->next_node,ply_count++){ |
| 870 | /* write the move number */ |
| 871 | if (ply->player == white){ |
| 872 | rb->snprintf(buffer,10,"%u.",(ply_count/2)+1); |
| 873 | write_pgn_token(fhandler, buffer, &line_length); |
| 874 | } |
| 875 | /* write the actual move */ |
| 876 | write_pgn_token(fhandler,ply->pgn_text,&line_length); |
| 877 | /* write the result of the game at the end */ |
| 878 | if (ply->checkmate){ |
| 879 | if (ply->player == white){ |
| 880 | write_pgn_token(fhandler,"1-0",&line_length); |
| 881 | } else { |
| 882 | write_pgn_token(fhandler,"0-1",&line_length); |
| 883 | } |
| 884 | break; |
| 885 | } else if (ply->draw){ |
| 886 | write_pgn_token(fhandler,"1/2-1/2",&line_length); |
| 887 | break; |
| 888 | } else if (ply->next_node->player == neutral) { |
| 889 | /* unknown end of the game */ |
| 890 | write_pgn_token(fhandler,"*",&line_length); |
| 891 | break; |
| 892 | } |
| 893 | } |
| 894 | |
| 895 | /* leave a blank line between the tag section and the game section */ |
| 896 | rb->fdprintf(fhandler,"\n\n"); |
| 897 | |
| 898 | rb->close(fhandler); |
| 899 | } |