How to Classify Positions with an ECO Opening Book
This guide demonstrates how to load an Encyclopaedia of Chess Openings (ECO) book file and classify board positions to determine their canonical ECO codes (e.g. C68) and descriptive opening names (e.g. Ruy Lopez, Exchange Variation) using the libscid C ABI.
1. Overview of Symbols
scid_eco_book_load: Loads and parses an ECO opening file (such asscid.eco) into a searchablescid_eco_bookhandle.scid_eco_book_code_find: Identifies the most specific ECO code matching a given board position.scid_eco_code_to_string: Converts a numericscid_eco_codeinto a standard alphanumeric string (e.g."C68").SCID_ECO_STRING_CAPACITY: Compile-time buffer capacity constant for ECO code string output.scid_eco_book_name_find: Retrieves the full human-readable opening name associated with an ECO code or position.scid_eco_book_free: Deallocates the ECO book handle.
2. Complete Recipe
#include <scid/scid.h>
#include <stdio.h>
#include <string.h>
static int
check(
scid_error error,
const char* call)
{
if (error == SCID_OK)
{
return 1;
}
fprintf(stderr, "%s failed with scid_error %hu\n", call, error);
return 0;
}
static int
play(
scid_position** position,
const char* san)
{
scid_position* next_position = NULL;
if (!check(
scid_position_create_with_san(*position, san, &next_position),
"scid_position_create_with_san"))
{
scid_position_free(next_position);
return 0;
}
scid_position_free(*position);
*position = next_position;
return 1;
}
static int
text_equals(
const char* text,
size_t text_size,
const char* expected)
{
return text_size == strlen(expected) && strncmp(text, expected, text_size) == 0;
}
int
main(void)
{
const char* standard_fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
scid_eco_book* book = NULL;
scid_position* position = NULL;
scid_eco_code code = SCID_ECO_NONE;
char code_text[SCID_ECO_STRING_CAPACITY];
char name[128];
char fen[256];
size_t code_size = 0;
size_t name_size = 0;
size_t fen_size = 0;
if (!check(scid_eco_book_load(LIBSCID_EXAMPLE_ECO_FILE, &book), "scid_eco_book_load") ||
!check(
scid_position_create_from_fen(standard_fen, &position),
"scid_position_create_from_fen") ||
!play(&position, "d4") || !play(&position, "d5") || !play(&position, "c4") ||
!play(&position, "e6") ||
!check(
scid_position_to_fen(position, fen, sizeof(fen), &fen_size), "scid_position_to_fen") ||
!check(scid_eco_book_code_find(book, position, &code), "scid_eco_book_code_find") ||
!check(
scid_eco_code_to_string(
code, SCID_ECO_FORMAT_BASIC, code_text, sizeof(code_text), &code_size),
"scid_eco_code_to_string") ||
!check(
scid_eco_book_name_find(book, position, name, sizeof(name), &name_size),
"scid_eco_book_name_find"))
{
scid_position_free(position);
scid_eco_book_free(book);
return 1;
}
printf("position: %.*s\n", (int)fen_size, fen);
printf("eco code: %.*s\n", (int)code_size, code_text);
printf("eco name: %.*s\n", (int)name_size, name);
if (!text_equals(code_text, code_size, "D30") ||
!text_equals(name, name_size, "Queen's Gambit Declined"))
{
scid_position_free(position);
scid_eco_book_free(book);
return 1;
}
scid_position_free(position);
scid_eco_book_free(book);
return 0;
}
3. Key Concepts and Patterns
Loading Books and Resolving Openings
scid_eco_book* book = NULL;
scid_eco_book_load("share/scid/scid.eco", &book);
scid_eco_code code = SCID_ECO_NONE;
scid_eco_book_code_find(book, position, &code);
char code_str[SCID_ECO_STRING_CAPACITY];
size_t code_str_size = 0;
scid_eco_code_to_string(code, code_str, sizeof(code_str), &code_str_size);
char opening_name[128];
size_t name_size = 0;
scid_eco_book_name_find(book, position, opening_name, sizeof(opening_name), &name_size);
printf("ECO: %.*s - %.*s\n", (int)code_str_size, code_str, (int)name_size, opening_name);
scid_eco_book_free(book);