Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Communicate with a Chess engine in Python?

On Windows 7 I can communicate with a chess engine via command line. Small Example Session with Stockfish on Win 7:

C:\run\Stockfish>stockfish-x64.exe
Stockfish 2.2.2 JA SSE42 by Tord Romstad, Marco Costalba and Joona Kiiski
quit

C:\run\Stockfish>

The first line was output by the engine and the 'quit' was what I typed to quit the engine (There are other things I can do, but that's clear to me).

Now I want to communicate with that engine from python:

import subprocess
engine = subprocess.Popen(
    'stockfish-x64.exe',
    stdin=subprocess.PIPE,
    stdout=subprocess.PIPE,
)
for line in engine.stdout:
    print(line.strip())
engine.stdin.write('quit\n')

and i get

C:\run\Stockfish>communicate.py
b'Stockfish 2.2.2 JA SSE42 by Tord Romstad, Marco Costalba and Joona Kiiski'

But it doesn't quit the engine (no C:\run\Stockfish> prompt), it keeps waiting for input. I have to close the window by hand. It seems not to get my quit message (last line of the python script) written to stdin.

In other words, I can read from stdout but when I write to stdin nothing happens.

What am I doing wrong and how to do it right?

like image 725
Nils Lindemann Avatar asked Sep 09 '12 18:09

Nils Lindemann


2 Answers

You've got a deadlock: the subprocess is waiting for input, while your program is waiting for it to output more lines in

for line in engine.stdout:
    print(line.strip())

This loop only stops when the subprocess closes its stdout.

like image 84
Fred Foo Avatar answered Sep 28 '22 04:09

Fred Foo


You might want to use asyncio like python-chess does. See

engine.py

and the example from the documentation

import asyncio
import chess
import chess.engine

    async def main():
        transport, engine = await chess.engine.popen_uci("/usr/bin/stockfish")

        board = chess.Board()
        while not board.is_game_over():
            result = await engine.play(board, chess.engine.Limit(time=0.1))
            board.push(result.move)

        await engine.quit()

    asyncio.set_event_loop_policy(chess.engine.EventLoopPolicy())
    asyncio.run(main())
like image 44
Wolfgang Fahl Avatar answered Sep 28 '22 03:09

Wolfgang Fahl