Skip to content

isofarro/chess-opening-trees

Repository files navigation

Chess Opening Trees

Creates opening trees from PGN files. The tree is an SQLite database.

Python and uv set-up

python3 -m venv .venv
source .venv/bin/activate
pip install uv

Installation

git clone https://github.com/isofarro/chess-opening-trees.git
cd chess-opening-trees
uv install

Usage

Building a tree from PGN files

We build a tree from one or more PGN files. We can run the build repeatedly until all the PGN files we want to add are added. This means we can update the opening tree regularly, as new game databases are available.

./tree.py build \
    --tree my_tree.tree \
    --max-ply 60 \
    --min-rating 2000 \
    pgn/

The build keeps track of files it's imported, and skips them if there are no changes (file modification date, content hash). So you can run it multiple times against a directory, and it imports any new files found in the directory. Perfect for regularly updating a tree with weekly TWIC files.

Pruning the tree of one game positions to a specific depth

This removes positions that have been visited once, and not within a specific depth of the last position with more than one game.

./tree.py prune \
    my_tree.tree \
    --max-closeness 5
    --batch-size 2000
  • --max-closeness is the number of plies from a position that has more than 1 visit. Defaults to 5.
  • --batch-size is the number of positions to delete in each transaction. defaults to 1000.

Each 1-game position has a game reference, so it's feasible when the tree grows to reach the leaf position to re-process the game and add in some more moves.

Opening tree queries

Query the opening tree by position

./tree.py query
    my_tree.tree
    --fen "r1bq1rk1/2p1bppp/p1np1n2/1p2p3/4P3/1BP2N1P/PP1P1PP1/RNBQR1K1 b - - 0 9"
    --output json
  • fen is the FEN string of the position
  • output is the format of the output. Defaults to json.

The JSON output looks like this:

{
  "fen": "rn1qkb1r/ppp1pppp/5nb1/4N3/3P2P1/2N4P/PPP5/R1BQKB1R b KQkq -",
  "moves": [
    {
      "move": "e6",
      "fen": "rn1qkb1r/ppp2ppp/4pnb1/4N3/3P2P1/2N4P/PPP5/R1BQKB1R w KQkq -",
      "total_games": 3333,
      "white_wins": 2006,
      "draws": 160,
      "black_wins": 1167,
      "last_played_date": "2025-05-31",
      "rating": 2154,
      "performance": 2059
    },
    ...
  ]
}

HTTP JSON API

Using command line arguments

    ./tree.py serve \
    --trees bdg-cce pgn/openings/D00-bdg-games-cce-2025-05.tree \
    --port 2882

Using a configuration file

    ./tree.py serve --config serve-config.json

The configuration file is in JSON format:

{
  "port": 3000,
  "trees": [
    {
      "name": "main",
      "file": "trees/twic-2025.tree"
    },
    {
      "name": "bdg",
      "file": "pgn/openings/D00-bdg-games-cce-2025-05.tree"
    }
  ]
}

Reverse proxy base URL

When running behind a proxy (e.g., Nginx), set baseUrl in the config. Returned links in the API responses use this public base URL instead of http://localhost:{port}.

{
  "baseUrl": "https://openingtrees.example.com/api",
  "port": 2882,
  "trees": [
    { "name": "main", "file": "trees/twic-2025.tree" }
  ]
}

The server still binds locally to localhost:2882; the baseUrl only affects the URLs returned by the API (e.g., tree paths).

Both methods start an HTTP server. The server supports multiple trees, each specified by name and tree file path. Command line arguments take precedence over config file settings.

Using WSGI with uvicorn (Production)

For production deployment with nginx or other reverse proxies, use the WSGI application:

# Install dependencies
uv install

# Run with uvicorn directly
export OPENING_TREE_CONFIG=serve-config.json
uvicorn opening_tree.wsgi:app --host 0.0.0.0 --port 8000

# Or use the convenience script
python run_wsgi.py --config serve-config.json --port 8000 --host 0.0.0.0

The WSGI application provides the same API endpoints as the HTTP server but is designed for production use with proper ASGI servers like uvicorn.

Nginx Configuration

For production deployment with a domain name, use Nginx as a reverse proxy. An example configuration is provided in .

To set up:

  1. Start the WSGI application:

    # Run on localhost (Nginx will proxy to this)
    export OPENING_TREE_CONFIG=local-config.json
    uvicorn opening_tree.wsgi:app --host 127.0.0.1 --port 8000
  2. Configure Nginx:

    # Copy and modify the example config
    sudo cp nginx-example.conf /etc/nginx/sites-available/openingtrees
    
    # Edit the configuration
    sudo nano /etc/nginx/sites-available/openingtrees
    # - Replace 'openingtrees.example.com' with your domain
    # - Update SSL certificate paths
    # - Adjust rate limiting and other settings as needed
    
    # Enable the site
    sudo ln -s /etc/nginx/sites-available/openingtrees /etc/nginx/sites-enabled/
    sudo nginx -t  # Test configuration
    sudo systemctl reload nginx
  3. Set up SSL certificates (using Let's Encrypt):

    sudo certbot --nginx -d openingtrees.example.com

The Nginx configuration includes:

  • HTTPS redirect and SSL termination
  • Security headers and rate limiting
  • CORS support for web frontends
  • Gzip compression
  • Health check endpoint
  • Load balancing support (commented out)

The URL to query a position in an opening tree is the pattern http://localhost:2882/{tree}/{fen} where:

  • {tree} is the name of the tree defined in the serve command
  • {fen} is the FEN string of the position, URL encoded.
curl http://localhost:2882/bdg-cce/rn1qkb1r%2Fpp2pppp%2F2p2n2%2F8%2F3P4%2F2N2Q1P%2FPPP3P1%2FR1B1KB1R%20w%20KQkq%20-%200%208

This returns a JSON response in the same structure as the query command above.

We can get a list of trees by doing a GET on http://localhost:2882/, this returns the payload:

[
  {
    "name": "main",
    "path": "http://localhost:2882/main/"
  },
  {
    "name": "bdg-cce",
    "path": "http://localhost:2882/bdg-cce/"
  }
]

Append the URL-encoded FEN to the tree path to query a position, e.g. http://localhost:2882/main/<encoded_fen>.

About

Generate opening trees from PGN

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors