1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
3 Copyright (C) 2002-2024 Ben Kibbey <bjk@luxsci.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #define PGN_TIME_FORMAT "%Y.%m.%d"
23 #define MAX_PGN_LINE_LEN 255
24 #define MAX_SAN_MOVE_LEN 7
27 #define VALIDRANK VALIDFILE
28 #define VALIDFILE(f) (f >= 1 && f <= 8)
29 #define RANKTOBOARD(r) (8 - r)
30 #define FILETOBOARD(c) (c - 1)
31 #define RANKTOINT(r) (r - '0')
32 #define FILETOINT(c) (c - ('a' - 1))
33 #define VALIDROW(r) (r >= '1' && r <= '8')
34 #define VALIDCOL(c) (c >= 'a' && c <= 'h')
35 #define INTTORANK(r) (r + '0')
36 #define INTTOFILE(f) (f + ('a' - 1))
38 #define SET_FLAG(var, f) (var |= f)
39 #define CLEAR_FLAG(var, f) (var &= ~(f))
40 #define TOGGLE_FLAG(var, f) (var ^= (f))
41 #define TEST_FLAG(var, f) (var & f)
45 OPEN_SQUARE
, PAWN
, BISHOP
, ROOK
, KNIGHT
, QUEEN
, KING
54 #define GF_PERROR 0x0001 /* Parse error for this game. */
55 #define GF_ENPASSANT 0x0002 /* For En Passant validation. */
56 #define GF_GAMEOVER 0x0004 /* End of game. */
57 #define GF_WK_CASTLE 0x0008
58 #define GF_WQ_CASTLE 0x0010
59 #define GF_BK_CASTLE 0x0020
60 #define GF_BQ_CASTLE 0x0040
61 #define GF_BLACK_OPENING 0x0080
68 unsigned char icon
; // The piece.
69 unsigned char valid
:1, /* != 0 if this square is a valid move for the
79 char *name
; // Tag name.
80 char *value
; // Tag value.
81 } __attribute__ ((packed
)) TAG
;
86 * g.hp is the pointer to the current history which may be .rav for
87 * Recursive Annotated Variations. The depth of recursion is kept track of in
90 typedef struct history
92 char *move
; // The SAN move text.
93 char *comment
; // Annotation for this move.
94 unsigned char nag
[MAX_PGN_NAG
]; // Numeric Annotation Glyph.
95 char *fen
; // Of the current board.
96 struct history
**rav
; // Variation of the current move.
100 * Keeps game state history for the root move.
104 char *fen
; // Game board state.
105 unsigned short flags
;
106 unsigned short hindex
;
107 HISTORY
**hp
; // Pointer to the root move.
111 * This is an array of 'games' structures. One for each game in a file, or
114 typedef struct game_s
116 TAG
**tag
; // Roster tags.
117 HISTORY
**history
; // Move history for this game.
118 HISTORY
**hp
; /* History pointer pointing to the location
119 in *history used mainly for RAV. */
120 RAV
*rav
; // Saved game states for the root move of RAV.
121 int ravlevel
; // An index to *rav.
122 unsigned short hindex
; // Current move in *hp.
123 unsigned short flags
; // Game flags.
124 unsigned short oflags
; // Game flags for the previous move.
125 unsigned char side
:1, // This playing side. BLACK or WHITE.
126 turn
:1; // BLACK or WHITE.
127 unsigned short ply
; // Move count.
128 void *data
; /* User data associated with this game. Must
129 * be freed by the user. */
130 // internal validation state
146 * Global GAME array. pgn_new_game() appends to this array.
151 * 'gindex' and 'gtotal' are the current and total number of games in 'game'.
153 extern int gindex
, gtotal
;
156 * Library configuration flags. These will affect all games.
161 * When pgn_write() is called to write a game, write reduced PGN format.
162 * This will only write the seven tag roster and move text skipping any
163 * annotation. The type for this flag is an int.
168 * The number of full moves to write per line. If 0 then pgn_write() will
169 * write as many as possible within 80 columns. The type for this flag
175 * Normally when a parse error occurs in a game the game is flagged with
176 * GF_PERROR and the rest of the game is discarded and processing of the
177 * next game is done. When set and a parse error occurs the rest of the
178 * entire file will be discarded. The type for this flag is an int.
184 * If the following is set to a value > 0 and DEBUG was defined
185 * at compile time then debugging output will be written to
186 * "libchess.debug" in the current directory.
192 * After PGN_PROGRESS amount of bytes have been read from a file, call
193 * PGN_PROGRESS_FUNC. The type for PGN_PROGRESS is a long.
194 * PGN_PROGRESS_FUNC is of type pgn_progress.
200 * If set to 1 and an opponent can attack a castling square the castling
201 * move will not be a valid one.
207 * Errors returned from the following functions.
222 char *tmpfile
; /* For appending. */
227 * The prototype of the PGN_PROGRESS_FUNC function pointer.
229 typedef void (*pgn_progress
) (long size
, long offset
);
232 * Sets config flag 'f' to the next argument. Returns E_PGN_OK on success or
233 * E_PGN_ERR if 'f' is an invalid flag or E_PGN_INVALID if 'val' is an invalid
236 pgn_error_t
pgn_config_set (pgn_config_flag f
, ...);
239 * Gets the value of config flag 'f'. The next argument should be a pointer of
240 * the config type which is set to the value of 'f'. Returns E_PGN_ERR if 'f'
241 * is an invalid flag or E_PGN_OK on success.
243 pgn_error_t
pgn_config_get (pgn_config_flag f
, ...);
246 * Returns E_PGN_OK if 'filename' is a recognized compressed filetype or
249 pgn_error_t
pgn_is_compressed (const char *filename
);
252 * Opens a file 'filename' with the given 'mode'. 'mode' should be "r" for
253 * reading, "w" for writing (will truncate if the file exists) or "a" for
254 * appending to an existing file or creating a new one. Returns E_PGN_OK on
255 * success and sets 'result' to a file handle for use will the other file
256 * functions or E_PGN_ERR if there is an error opening the file in which case
257 * errno will be set to the error or E_PGN_INVALID if 'mode' is an invalid
258 * mode or if 'filename' is not a regular file.
260 pgn_error_t
pgn_open (const char *filename
, const char *mode
,
264 * Closes and free's a PGN file handle. Returns E_PGN_OK on success,
265 * E_PGN_INVALID if 'pgn' is NULL, or E_PGN_ERR if rename() failed.
267 pgn_error_t
pgn_close (PGN_FILE
* pgn
);
270 * Parses a PGN_FILE which was opened with pgn_open(). If 'pgn' is NULL then a
271 * single empty game will be allocated. If there is a parsing error
272 * E_PGN_PARSE is returned, if there was a memory allocation error E_PGN_ERR
273 * is returned, otherwise E_PGN_OK is returned and the global 'gindex' is set
274 * to the last parsed game in the file and the global 'gtotal' is set to the
275 * total number of games in the file. The file should be closed with
276 * pgn_close() after processing.
278 pgn_error_t
pgn_parse (PGN_FILE
* pgn
);
281 * Allocates a new game and increments 'gtotal'. 'gindex' is then set to the
282 * new game. Returns E_PGN_ERR if there was a memory allocation error or
283 * E_PGN_OK on success.
285 pgn_error_t
pgn_new_game ();
288 * Writes a PGN formatted game 'g' to a file which was opened with pgn_open().
289 * See 'pgn_config_flag' for output options. Returns E_PGN_ERR if there was a
290 * memory allocation or write error and E_PGN_OK on success.
292 pgn_error_t
pgn_write (PGN_FILE
* pgn
, GAME g
);
295 * Frees all games in the global 'game' array. Returns nothing.
297 void pgn_free_all (void);
300 * Frees a single game 'g'. Returns nothing.
302 void pgn_free (GAME g
);
305 * Adds a tag 'name' with value 'value' to the pointer to array of TAG
306 * pointers 'dst'. If a duplicate tag 'name' was found then the existing tag
307 * is updated to the new 'value'. If 'value' is NULL, the tag is removed.
308 * Returns E_PGN_ERR if there was a memory allocation error or E_PGN_OK on
311 pgn_error_t
pgn_tag_add (TAG
*** dst
, char *name
, char *value
);
314 * Returns the total number of tags in 't' or 0 if 't' is NULL.
316 int pgn_tag_total (TAG
** t
);
319 * Finds a tag 'name' in the structure array 't'. Returns the location in the
320 * array of the found tag or E_PGN_ERR if the tag could not be found.
322 pgn_error_t
pgn_tag_find (TAG
** t
, const char *name
);
325 * Sorts a tag array. The first seven tags are in order of the PGN standard so
326 * don't sort'em. Returns nothing.
328 void pgn_tag_sort (TAG
** t
);
331 * Frees a TAG array. Returns nothing.
333 void pgn_tag_free (TAG
**);
336 * It initializes the board (b) to the FEN tag (if found) and sets the
337 * castling and enpassant info for the game 'g'. If 'fen' is set it should be
338 * a fen tag and will be parsed rather than the game 'g'.tag FEN tag. Returns
339 * E_PGN_OK on success or if there was both a FEN and SetUp tag with the SetUp
340 * tag set to 0. Returns E_PGN_PARSE if there was a FEN parse error, E_PGN_ERR
341 * if there was no FEN tag or there was a SetUp tag with a value of 0. Returns
342 * E_PGN_OK on success.
344 pgn_error_t
pgn_board_init_fen (GAME g
, BOARD b
, char *fen
);
347 * Creates a FEN tag from the current game 'g', history move (g.hindex) and
348 * board 'b'. Returns a FEN tag.
350 char *pgn_game_to_fen (GAME g
, BOARD b
);
353 * Resets or initializes a new game board 'b'. Returns nothing.
355 void pgn_board_init (BOARD b
);
358 * Valididate move 'm' against the game state 'g' and game board 'b' and
359 * update board 'b'. 'm' is ensured to be in SAN format and 'frfr' will the
360 * file/rank representation of 'm' and should be freed. Returns E_PGN_PARSE if
361 * there was a move text parsing error, E_PGN_INVALID if the move is invalid,
362 * E_PGN_AMBIGUOUS if the move is invalid with ambiguities or E_PGN_OK if
365 pgn_error_t
pgn_parse_move (GAME g
, BOARD b
, char **m
, char **frfr
);
368 * Like pgn_parse_move() but don't modify game flags in 'g' or board 'b'.
370 pgn_error_t
pgn_validate_move (GAME g
, BOARD b
, char **m
, char **frfr
);
373 * Returns the total number of moves in 'h' or 0 if there are none.
375 int pgn_history_total (HISTORY
** h
);
378 * Returns the history ply 'n' from 'h'. If 'n' is out of range then NULL is
381 HISTORY
*pgn_history_by_n (HISTORY
** h
, int n
);
384 * Appends move 'm' to game 'g' history pointer and creates a FEN tag for the
385 * current game state using board 'b'. The FEN tag makes things faster than
386 * validating the entire move history by validating only the current move to
387 * the previous moves FEN tag. The history pointer may be a in a RAV so
388 * g->rav.hp is also updated to the new (realloc()'ed) pointer. If not in a
389 * RAV then g->history will be updated. Returns E_PGN_ERR if realloc() failed
390 * or E_PGN_OK on success.
392 pgn_error_t
pgn_history_add (GAME g
, BOARD b
, const char *m
);
395 * Deallocates all of the history data from position 'start' in the array 'h'.
398 void pgn_history_free (HISTORY
** h
, int start
);
401 * Resets the game 'g' using board 'b' up to history move (g.hindex) 'n'.
402 * Returns E_PGN_OK on success or E_PGN_PARSE if there was a FEN tag but the
403 * parsing of it failed. Or returns E_PGN_INVALID if somehow the move failed
404 * validation while resetting.
406 pgn_error_t
pgn_board_update (GAME g
, BOARD b
, int n
);
409 * Updates the game 'g' using board 'b' to the next 'n'th history move.
412 void pgn_history_prev (GAME g
, BOARD b
, int n
);
415 * Updates the game 'g' using board 'b' to the previous 'n'th history move.
418 void pgn_history_next (GAME g
, BOARD b
, int n
);
421 * Converts the character piece 'p' to an integer. Returns the integer
422 * associated with 'p' or E_PGN_ERR if 'p' is invalid.
424 int pgn_piece_to_int (int p
);
427 * Converts the integer piece 'n' to a character whose turn is 'turn'. WHITE
428 * piece are uppercase and BLACK pieces are lowercase. Returns the character
429 * associated with 'n' or E_PGN_ERR if 'n' is an invalid piece.
431 pgn_error_t
pgn_int_to_piece (char turn
, int n
);
434 * Toggles g->turn. Returns nothing.
436 void pgn_switch_turn (GAME
);
439 * Toggles g->side and switches the White and Black roster tags. Returns
442 void pgn_switch_side (GAME g
, int t
);
445 * Clears the enpassant flag for all positions on board 'b'. Returns nothing.
447 void pgn_reset_enpassant (BOARD b
);
450 * Clears the valid move flag for all positions on board 'b'. Returns nothing.
452 void pgn_reset_valid_moves (BOARD b
);
455 * Sets valid moves (b.valid) from game 'g' using board 'b'. The valid moves
456 * are for the piece on the board 'b' at 'rank' and 'file'. Returns nothing.
458 void pgn_find_valid_moves (GAME g
, BOARD b
, int rank
, int file
);
461 * Returns the version string of the library.
463 const char *pgn_version (void);