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")
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.