2 Copyright (c) 1993 Richard V. Nash.
3 Copyright (c) 2000 Dan Papasian
4 Copyright (C) Andrew Tridgell 2002
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 /* One line has everything on it */
25 static int WriteMoves(FILE * fp, struct move_t *m)
27 unsigned long MoveInfo = (m->color == BLACK);
29 int useFile = 0, useRank = 0, check = 0;
32 castle = (m->moveString[0] == 'o');
36 piece = piecetype(CharToPiece(m->moveString[0]));
38 MoveInfo = (MoveInfo <<= 3) | piece;
39 MoveInfo = (MoveInfo <<= 3) | m->fromFile;
40 MoveInfo = (MoveInfo <<= 3) | m->fromRank;
41 MoveInfo = (MoveInfo <<= 3) | m->toFile;
42 MoveInfo = (MoveInfo <<= 3) | m->toRank;
43 MoveInfo = (MoveInfo <<= 3) | (m->pieceCaptured & 7);
44 MoveInfo = (MoveInfo <<= 3) | (m->piecePromotionTo & 7);
45 MoveInfo = (MoveInfo <<= 1) | (m->enPassant != 0);
47 /* Are we using from-file or from-rank in algString? */
48 i = strlen(m->algString) - 1;
49 if (m->algString[i] == '+') {
53 if (piece != PAWN && !castle) {
57 if (m->algString[i] == 'x')
61 if (isdigit(m->algString[i])) {
67 useFile = (islower(m->algString[i]) ? 4 : 0);
69 MoveInfo = (MoveInfo << 3) | useFile | useRank | check;
70 fprintf(fp, "%lx %x %x\n", MoveInfo, m->tookTime, m->atTime);
76 static int ReadMove(FILE * fp, struct move_t *m)
78 char line[MAX_GLINE_SIZE];
79 fgets(line, MAX_GLINE_SIZE - 1, fp);
80 if (sscanf(line, "%d %d %d %d %d %d %d %d %d \"%[^\"]\" \"%[^\"]\" %u %u\n",
81 &m->color, &m->fromFile, &m->fromRank, &m->toFile, &m->toRank,
82 &m->pieceCaptured, &m->piecePromotionTo, &m->enPassant, &m->doublePawn,
83 m->moveString, m->algString, &m->atTime, &m->tookTime) != 13)
89 static void WriteGameState(FILE * fp, struct game_state_t *gs)
93 for (i = 0; i < 8; i++)
94 for (j = 0; j < 8; j++) {
95 fprintf(fp, "%c", PieceToChar(gs->board[i][j]));
97 fprintf(fp, "%d %d %d %d %d %d",
98 gs->wkmoved, gs->wqrmoved, gs->wkrmoved,
99 gs->bkmoved, gs->bqrmoved, gs->bkrmoved);
100 for (i = 0; i < 8; i++)
101 fprintf(fp, " %d %d", gs->ep_possible[0][i], gs->ep_possible[1][i]);
102 fprintf(fp, " %d %d %d\n", gs->lastIrreversable, gs->onMove, gs->moveNum);
107 static void WriteGameFile(FILE * fp, int g)
110 struct game *gg = &game_globals.garray[g];
111 struct player *wp = &player_globals.parray[gg->white], *bp = &player_globals.parray[gg->black];
113 fprintf(fp, "v %d\n", GAMEFILE_VERSION);
114 fprintf(fp, "%s %s\n", wp->name, bp->name);
115 fprintf(fp, "%d %d\n", gg->white_rating, gg->black_rating);
116 fprintf(fp, "%d %d %d %d\n", gg->wInitTime, gg->wIncrement,
117 gg->bInitTime, gg->bIncrement);
118 fprintf(fp, "%lx\n", gg->timeOfStart);
119 fprintf(fp, "%d %d\n",
120 (net_globals.con[wp->socket]->timeseal ? gg->wRealTime/100 : gg->wTime),
121 (net_globals.con[bp->socket]->timeseal ? gg->bRealTime/100 : gg->bTime));
122 fprintf(fp, "%d %d\n", gg->result, gg->winner);
123 fprintf(fp, "%d %d %d %d\n", gg->private, gg->type,
124 gg->rated, gg->clockStopped);
125 fprintf(fp, "%d\n", gg->numHalfMoves);
126 for (i = 0; i < game_globals.garray[g].numHalfMoves; i++) {
127 WriteMoves(fp, &game_globals.garray[g].moveList[i]);
129 /* took out the next 3 lines to see if it helps with the crash bug we are
130 having on examine... fb 2.25.96 */
131 /* The next three lines stop wild games crashing the system - they are vital.
132 I fixed the problem with examine - don't remove these again - DAV */
133 if (strcmp(gg->FENstartPos, INITIAL_FEN) != 0)
134 fprintf (fp, "%s\n",gg->FENstartPos);
136 fprintf (fp, "d w\n");
137 WriteGameState(fp, &game_globals.garray[g].game_state);
143 static int ReadGameState(FILE * fp, struct game_state_t *gs, int version)
147 int wkmoved, wqrmoved, wkrmoved, bkmoved, bqrmoved, bkrmoved;
150 for (i = 0; i < 8; i++)
151 for (j = 0; j < 8; j++)
152 if (fscanf(fp, "%d ", &gs->board[i][j]) != 1)
155 for (i = 0; i < 8; i++)
156 for (j = 0; j < 8; j++) {
157 pieceChar = getc(fp);
158 gs->board[i][j] = CharToPiece(pieceChar, NULL);
161 if (fscanf(fp, "%d %d %d %d %d %d",
162 &wkmoved, &wqrmoved, &wkrmoved,
163 &bkmoved, &bqrmoved, &bkrmoved) != 6)
165 gs->wkmoved = wkmoved;
166 gs->wqrmoved = wqrmoved;
167 gs->wkrmoved = wkrmoved;
168 gs->bkmoved = bkmoved;
169 gs->bqrmoved = bqrmoved;
170 gs->bkrmoved = bkrmoved;
171 for (i = 0; i < 8; i++)
172 if (fscanf(fp, " %d %d", &gs->ep_possible[0][i], &gs->ep_possible[1][i]) != 2)
174 if (fscanf(fp, " %d %d %d\n", &gs->lastIrreversable, &gs->onMove, &gs->moveNum) != 3)
180 static int got_attr_value(int g, char *attr, char *value, FILE * fp)
184 if (!strcmp(attr, "w_init:")) {
185 game_globals.garray[g].wInitTime = atoi(value);
186 } else if (!strcmp(attr, "w_inc:")) {
187 game_globals.garray[g].wIncrement = atoi(value);
188 } else if (!strcmp(attr, "b_init:")) {
189 game_globals.garray[g].bInitTime = atoi(value);
190 } else if (!strcmp(attr, "b_inc:")) {
191 game_globals.garray[g].bIncrement = atoi(value);
192 } else if (!strcmp(attr, "white_name:")) {
193 strcpy(game_globals.garray[g].white_name, value);
194 } else if (!strcmp(attr, "black_name:")) {
195 strcpy(game_globals.garray[g].black_name, value);
196 } else if (!strcmp(attr, "white_rating:")) {
197 game_globals.garray[g].white_rating = atoi(value);
198 } else if (!strcmp(attr, "black_rating:")) {
199 game_globals.garray[g].black_rating = atoi(value);
200 } else if (!strcmp(attr, "result:")) {
201 game_globals.garray[g].result = atoi(value);
202 } else if (!strcmp(attr, "timestart:")) {
203 game_globals.garray[g].timeOfStart = atoi(value);
204 } else if (!strcmp(attr, "w_time:")) {
205 game_globals.garray[g].wTime = atoi(value);
206 } else if (!strcmp(attr, "b_time:")) {
207 game_globals.garray[g].bTime = atoi(value);
208 } else if (!strcmp(attr, "clockstopped:")) {
209 game_globals.garray[g].clockStopped = atoi(value);
210 } else if (!strcmp(attr, "rated:")) {
211 game_globals.garray[g].rated = atoi(value);
212 } else if (!strcmp(attr, "private:")) {
213 game_globals.garray[g].private = atoi(value);
214 } else if (!strcmp(attr, "type:")) {
215 game_globals.garray[g].type = atoi(value);
216 } else if (!strcmp(attr, "halfmoves:")) {
217 game_globals.garray[g].numHalfMoves = atoi(value);
218 if (game_globals.garray[g].numHalfMoves == 0)
220 game_globals.garray[g].moveListSize = game_globals.garray[g].numHalfMoves;
221 game_globals.garray[g].moveList = (struct move_t *) malloc(sizeof(struct move_t) * game_globals.garray[g].moveListSize);
222 for (i = 0; i < game_globals.garray[g].numHalfMoves; i++) {
223 if (ReadMove(fp, &game_globals.garray[g].moveList[i])) {
224 d_printf( "CHESSD: Trouble reading moves\n");
228 } else if (!strcmp(attr, "gamestate:")) { /* Value meaningless */
229 if (game_globals.garray[g].status != GAME_EXAMINE && game_globals.garray[g].status != GAME_SETUP &&
230 ReadGameState(fp, &game_globals.garray[g].game_state, 0)) {
231 d_printf( "CHESSD: Trouble reading game state\n");
235 d_printf( "CHESSD: Error bad attribute >%s<\n", attr);
240 static void ReadOneV1Move(FILE * fp, struct move_t *m)
244 int useFile, useRank, check, piece;
245 unsigned long MoveInfo;
247 fscanf(fp, "%lx %x %x", &MoveInfo, &m->tookTime, &m->atTime);
248 check = MoveInfo & 1;
249 useRank = MoveInfo & 2;
250 useFile = MoveInfo & 4;
252 m->enPassant = MoveInfo & 1; /* may have to negate later. */
254 m->piecePromotionTo = MoveInfo & 7; /* may have to change color. */
256 m->pieceCaptured = MoveInfo & 7; /* may have to change color. */
258 m->toRank = MoveInfo & 7;
260 m->toFile = MoveInfo & 7;
262 m->fromRank = MoveInfo & 7;
264 m->fromFile = MoveInfo & 7;
266 piece = MoveInfo & 7;
268 m->color = (MoveInfo & 8) ? BLACK : WHITE;
269 if (m->pieceCaptured != NOPIECE) {
270 if (m->color == BLACK)
271 m->pieceCaptured |= WHITE;
273 m->pieceCaptured |= BLACK;
277 if ((m->toRank == 3 && m->fromRank == 1)
278 || (m->toRank == 4 && m->fromRank == 6))
279 m->doublePawn = m->toFile;
282 if (m->pieceCaptured)
283 sprintf(m->algString, "%cx%c%d", 'a' + m->fromFile,
284 'a' + m->toFile, m->toRank + 1);
286 sprintf(m->algString, "%c%d", 'a' + m->toFile, m->toRank + 1);
287 if (m->piecePromotionTo != 0) {
288 if (m->piecePromotionTo == KNIGHT)
289 strcat(m->algString, "=N");
290 else if (m->piecePromotionTo == BISHOP)
291 strcat(m->algString, "=B");
292 else if (m->piecePromotionTo == ROOK)
293 strcat(m->algString, "=R");
294 else if (m->piecePromotionTo == QUEEN)
295 strcat(m->algString, "=Q");
296 m->piecePromotionTo |= m->color;
299 m->enPassant = m->toFile - m->fromFile;
302 PieceChar = PieceToChar(piecetype(piece) | WHITE);
303 if (PieceChar == 'K' && m->fromFile == 4 && m->toFile == 6) {
304 strcpy(m->algString, "O-O");
305 strcpy(m->moveString, "o-o");
306 } else if (PieceChar == 'K' && m->fromFile == 4 && m->toFile == 2) {
307 strcpy(m->algString, "O-O-O");
308 strcpy(m->moveString, "o-o-o");
311 m->algString[i++] = PieceChar;
313 m->algString[i++] = 'a' + m->fromFile;
315 m->algString[i++] = '1' + m->fromRank;
316 if (m->pieceCaptured != 0)
317 m->algString[i++] = 'x';
318 m->algString[i++] = 'a' + m->toFile;
319 m->algString[i++] = '1' + m->toRank;
320 m->algString[i] = '\0';
322 if (m->piecePromotionTo != 0) { // must be Shogi promotion
323 strcat(m->algString, "=+");
324 m->piecePromotionTo |= m->color;
327 if (m->algString[0] != 'O')
328 sprintf(m->moveString, "%c/%c%d-%c%d", PieceChar, 'a' + m->fromFile,
329 m->fromRank + 1, 'a' + m->toFile, m->toRank + 1);
331 strcat(m->algString, "+");
334 static int ReadV1Moves(struct game *g, FILE * fp)
338 g->moveListSize = g->numHalfMoves;
339 g->moveList = (struct move_t *) malloc(sizeof(struct move_t) * g->moveListSize);
340 for (i = 0; i < g->numHalfMoves; i++) {
341 ReadOneV1Move(fp, &g->moveList[i]);
346 static int ReadV1GameFmt(struct game *g, FILE * fp, int version)
349 char tmp[MAX_STRING_LENGTH];
352 fscanf(fp, "%s %s", g->white_name, g->black_name);
353 fscanf(fp, "%d %d", &g->white_rating, &g->black_rating);
354 fscanf(fp, "%d %d %d %d", &g->wInitTime, &g->wIncrement,
355 &g->bInitTime, &g->bIncrement);
356 if ((version < 3) && (!(g->bInitTime)))
357 g->bInitTime = g->wInitTime;
358 /*PRE-V3 assumed bInitTime was 0 if balanced clocks*/
359 fscanf(fp, "%lx", &g->timeOfStart);
360 fscanf(fp, "%d %d", &g->wTime, &g->bTime);
362 /* fixing an (apparently) old bug: winner not saved */
364 fscanf(fp, "%d %d", &result, &g->winner);
366 fscanf(fp, "%d", &result);
368 g->result = (enum gameend)result;
370 fscanf(fp, "%d %d %d %d", &g->private, (int *) &g->type,
371 &g->rated, &g->clockStopped);
372 fscanf(fp, "%d", &g->numHalfMoves);
376 getc(fp); /* Skip past a newline. */
378 fgets(tmp, MAX_LINE_SIZE, fp);
379 tmp [strlen(tmp)-1] = '\0'; /* kill the newline char */
381 if ((tmp[0] == '\0') || (!strcmp(tmp,"d w"))) {
382 /* default position */
383 strcpy (g->FENstartPos,INITIAL_FEN);
385 if (!strcmp(tmp,"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR"))
386 /* missing colour for default pos 1.7.1 bug */
387 strcpy(g->FENstartPos,INITIAL_FEN);
389 strcpy (g->FENstartPos,tmp);
390 FEN = g->FENstartPos;
391 while (*(FEN) != '/') { /* check for missing fen pos (1.7.1 bug) */
392 if (*(FEN++) == '\0') {
393 d_printf("Corrupt game %s vs %s!\n",g->white_name,g->black_name);
400 getc(fp); /* Skip past a newline. */
402 if (g->status != GAME_EXAMINE && g->status != GAME_SETUP) {
403 if (ReadGameState(fp, &g->game_state, version)) {
404 d_printf( "CHESSD: Trouble reading game state\n");
407 } else if (g->status == GAME_EXAMINE)
408 FEN_to_board(g->FENstartPos, &g->game_state);
413 int ReadGameAttrs_old(FILE * fp, int g,int version)
417 char line[MAX_GLINE_SIZE];
420 if ((ReadV1GameFmt(&game_globals.garray[g], fp, version)) < 0)
423 /* Read the game file here */
426 if ((len = strlen(line)) <= 1) {
427 fgets(line, MAX_GLINE_SIZE - 1, fp);
430 line[len - 1] = '\0';
431 attr = eatwhite(line);
433 continue; /* Comment */
434 value = eatword(attr);
436 d_printf( "CHESSD: Error reading file\n");
437 fgets(line, MAX_GLINE_SIZE - 1, fp);
442 value = eatwhite(value);
444 d_printf( "CHESSD: Error reading file\n");
445 fgets(line, MAX_GLINE_SIZE - 1, fp);
449 if (got_attr_value(g, attr, value, fp)) {
452 fgets(line, MAX_GLINE_SIZE - 1, fp);
454 if (!(game_globals.garray[g].bInitTime))
455 game_globals.garray[g].bInitTime = game_globals.garray[g].wInitTime;