Skip to content

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 as scid.eco) into a searchable scid_eco_book handle.
  • scid_eco_book_code_find: Identifies the most specific ECO code matching a given board position.
  • scid_eco_code_to_string: Converts a numeric scid_eco_code into 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);