Anmol's blog

How to determine your chess bot's ELO on Lichess

I recently got into chess programming. After creating my first bot, I wanted to estimate its ELO to get an indication of its skills. I personally this process a bit cumbersome. Therefore I wanted to create this guide, so others might have an easier time.

NOTE: As I am using a Mac, some details may be specific to MacOS.

Creating a chess bot

The first step is, naturally, to have a working chess bot. Preferably one that only makes legal moves. If you are only interested in creating the chess bot (and not implementing the chess move generation), I would highly recommend Sebastian Lague's Chess Challenge code. He also has some good videos on chess programming on YouTube.

Making your bot UCI compatible

UCI (Universal Chess Interface) is a chess communication protocol. It lets bots play against each other. This is what we want to do on Lichess, so that it can calculate an ELO for our bot.

If you build your bot using the Chess Challenge code, it won't have UCI support by default. I added it manually, and you can see the changes I made in this commit (this is based on a post on the Chess Challenge Discord). You can probably take inspiration from the changes in the commit even if you built your bot using some other code.

Connect your bot to Lichess

Once you have a chess bot that can play using the UCI protocol, you are ready to connect it to Lichess. You can do this through the lichess-bot code. It handles the complexity of communicating with Lichess bot API. Follow their guide on how to set it up here.

I had some trouble setting this up, so here are some tips:

Once you have successfully performed the steps above, it is time to edit the config.yml file. If you built your bot on the Chess Challenge code, you should change your config file to look like this:

token: "<yourTokenHere>" # Lichess OAuth2 Token.
url: "https://lichess.org/" # Lichess base URL.

engine: # Engine settings.
    dir: "/.../Chess-Challenge/Chess-Challenge/bin/Debug/net9.0"
    name: "Chess-Challenge.dll" # Binary name of the engine to use.
    interpreter: "dotnet"
    interpreter_options:
        - "uci"
        - "MyBot"
    working_dir: "/.../Chess-Challenge"
    protocol: "uci"

A couple things to note here:

I also made some changes in other places in the config.yml file:

Some modifications are also needed in the lichess-bot/lib/engine_wrapper.py file for the lichess-bot to properly work with your code. I made some changes to how the interpreter options were added to the command executed to run the chess bot binary. The beginning of the file should look like this:

def create_engine(engine_config: Configuration, game: Optional[model.Game] = None) -> EngineWrapper:

    cfg = engine_config.engine
    engine_path = os.path.abspath(os.path.join(cfg.dir, cfg.name))
    engine_type = cfg.protocol
    commands = []
    if cfg.interpreter:
        commands.append(cfg.interpreter)
        commands.append(engine_path)
        commands.extend(cfg.interpreter_options)
    if cfg.engine_options:
        for k, v in cfg.engine_options.items():
            commands.append(f"--{k}={v}" if v is not None else f"--{k}")

This instructs lichess-bot to run dotnet /.../Chess-Challenge/Chess-Challenge/bin/Debug/net9.0/Chess-Challenge.dll uci MyBot to start your bot. If you start your bot program in UCI mode using another command, you can edit the interpreter and interpreter options in the config.yml file so that the right command gets executed.

Finally, you might have to set execute permission on your chess bot's binary file. On Mac you can do this by running this command chmod +x /.../Chess-Challenge.dll.

NOTE: If you change your bot code and build your project again, you might have to give execute permissions again.

Hopefully, your bot should be able to play on Lichess and get an ELO rating now :) If you have any questions or comments feel free to reach out!