Overview
Download
Clone libpgn (latest) from the git repository:
git clone https://github.com/fwttnnn/libpgn
Installation
Compile libpgn as shared & static library:
cd libpgnmake
Test
Make sure libpgn works correctly (optional):
make test
PGN File Structure
[Event "RUDAR XXVIII - IM ROUND ROBIN"] [Site "Pozarevac, Serbia"] [Round "9.2"] [Date "2024.8.14"] [White "Ostojic, Nikola"] [Black "Ilincic, Zlatko"] [WhiteElo "2248"] [BlackElo "2274"] [Result "1/2-1/2"]
1.Nf3 d5 2.b3 c5 3.e3 Nc6 4.Bb2 Nf6 5.Bb5 Bd7 6.O-O e6 7.Bxc6 Bxc6 8.Ne5 1/2-1/2
.pgn file consists of 2 parts:
Usage (In a Nutshell)
#include <pgn.h>
#include <stdio.h>
int main(void)
{
pgn_t *pgn = pgn_init();
pgn_parse(pgn,
"[Event \"Global Championship Finals 2022\"]\n"
"[Result \"*\"]\n"
"\n"
"1. e4 e5 2. Ke2? *");
pgn_cleanup(pgn);
return 0;
}
Let's iterate through every pgn_* functions:
pgn_init: allocates heap memory for the librarypgn_parse: (core of the library) parses astringrepresentation of a pgn file, and puts the information onto thepgnvariablepgn_cleanup: cleans up the allocated heap memory
Accessing the Parsed Information
You can pull the parsed information through modules such as metadata.h, score.h, moves.h, and more:
#include <pgn.h>
#include <stdio.h>
int main(void)
{
pgn_t *pgn = pgn_init();
pgn_parse(pgn,
"[Event \"Global Championship Finals 2022\"]\n"
"[Result \"*\"]\n"
"\n"
"1. e4 e5 2. Ke2? *");
printf("%s\n", pgn_metadata_get(pgn->metadata, "Event"));
printf("Featuring 'Bongcloud Attack'\n\n");
for (int i = 0; i < pgn->moves->length; i++) {
pgn_move_t white = pgn->moves->values[i].white;
pgn_move_t black = pgn->moves->values[i].black;
printf("%d.\n %s\n %s\n", i + 1, white.notation, black.notation);
}
printf("%s\n", pgn_score_to_string(pgn->score));
pgn_cleanup(pgn);
return 0;
}
Output:
Global Championship Finals 2022 Featuring 'Bongcloud Attack' 1. e4 e5 2. Ke2? *
Libray Structure
Everything is self-documented. For starters, look into the pgn.h module:
typedef struct pgn_t {
pgn_metadata_t *metadata;
pgn_moves_t *moves;
pgn_score_t score;
} pgn_t;
The data structure of libpgn resembles the PGN file structure (see 4.) itself. If you're familiar with C, you can dig down (read the code) by yourself, since everything is self-documented.
Metadata (metadata.h):
typedef struct pgn_metadata_t {
__pgn_metadata_item_t *items;
size_t length, size;
} pgn_metadata_t;
typedef struct __pgn_metadata_item_t {
pgn_buffer_t *key;
pgn_buffer_t *value;
} __pgn_metadata_item_t;
Basically a hash map.
PGN_EXPORT void pgn_metadata_insert(pgn_metadata_t *metadata, char *key, char *value); PGN_EXPORT char *pgn_metadata_get(pgn_metadata_t *metadata, char *key); PGN_EXPORT void pgn_metadata_delete(pgn_metadata_t *metadata, char *key);
You can play with it using these functions. Generally, look for the one that has a PGN_EXPORT macro.
Moves (moves.h):
struct pgn_moves_t {
__pgn_moves_item_t *values;
size_t length;
size_t size;
};
struct __pgn_moves_item_t {
pgn_move_t white;
pgn_move_t black;
};
typedef struct pgn_move_t {
pgn_piece_t piece, promoted_to;
char notation[__PGN_MOVE_NOTATION_SIZE];
int castles;
bool captures;
bool en_passant;
pgn_check_t check;
pgn_coordinate_t from, dest;
pgn_annotation_t annotation;
pgn_comments_t *comments;
pgn_alternative_moves_t *alternatives;
} pgn_move_t;
An array that holds each move, it supports: annotation (!!, ?!, ??, etc.), comments ({hi}, {from libpgn}), alternative moves (69. Be4 ( 69. Be2 69... e4 ) 69... Rxe5?!), and more.
Quick tip: anything that has this signature (T *name) where T is a type is considered an array. The type name is usually plural (s).
Foreign Function Interface (FFI)
I am planning to add bindings for other languages (python, zig, etc.), there's one example for ada.