Search code examples
pythonchessuci

Response from my chess engine using Universal Chess Interface (UCI) isn't received by the chess GUI apps


I've coded some toy chess engines in the past using different languages, all of them providing their own simple text-based UI. Now I want to write an engine that can be used with chess GUIs like ChessX or Cute Chess. I've read and understood (at least I thought so) the Universal Chess Interface (UCI) protocol.

To get a first working version, I'm using Python (3.9 on macOS) for my engine, here's the part that's looking for input via STDIN a full (non-)working example as requested:

import sys
import os
import time
import re
import select
import fileinput


if __name__ == '__main__':
    while True:
        if select.select([sys.stdin, ], [], [], 0.0)[0]:
            for line in fileinput.input():
                tokens = [ x.strip().lower() for x in re.split("\s+", line.strip()) ]
                if tokens[0] == "uci":
                    sys.stdout.write("id name mychess\n")
                    sys.stdout.write("id author myname\n")
                    sys.stdout.write("uciok\n")
                elif tokens[0] == "isready":
                    sys.stdout.write("readyok\n")
        time.sleep(2)

When I put my engine in one of the GUIs (or a simple python-chess app, see below), my engine gets the initial "uci" command and answers accordingly as I can verify using some test and logging code not shown in the minimal example above.

But then, nothing happens ... until the GUIs are telling me they timed-out. Obviously, they didn't get any answer from my engine. Using the python-chess library, I can verify that the response from my engine isn't coming through to the GUI process.

This is the code in my python-chess app to connect to my engine:

engine = chess.engine.SimpleEngine.popen_uci(r"./engine.py")

If I put there the path to the stockfish engine, I can see the response from that engine and how the python-chess app answers with "ucinewgame" and a lot of other communication.

So, why is the response from my engine not read by the GUI client?

Update: I suspect it has something to do with the select code in my example. It's there to simulate non-blocking access to STDIN. In a simpler approach, I'm just using a blocking call to input and it works (here's the gist of it):

while True:
    line = input()
    if line.strip().lower() == "uci":
        print("id name mychess")
        print("uciok")

Solution

  • The problem seems to be in using select.select() and/or fileinput.input(). If I omit those fancy techniques and simply read from STDIN, everything works and cutechess accepts my engine. This is the basic code for a UCI chess engine to get recognized:

    import sys
    import os
    import re
    
    
    if __name__ == '__main__':
        while True:
            line = input()
            tokens = [ x.strip().lower() for x in re.split("\s+", line.strip()) ]
            if tokens[0] == "uci":
                sys.stdout.write("id name mychess\n")
                sys.stdout.write("id author myname\n")
                sys.stdout.write("uciok\n")
            elif tokens[0] == "isready":
                print("readyok")
    

    Of course, the blocking call to input() now doesn't allow for concurrent calculations in my engine while accepting input from the GUI immediately, but that's stuff for perhaps another question.