8

I'm trying to write a Linux command line UCI interface for Stockfish. My program writes a bunch of commands to a text file and then tries to pipe them to Stockfish via the command line. My problem is, whenever I try to analyse a position, the program exits almost immediately:

sf.txt:

position startpos moves e2e4
go movetime 5000

output:

~$ stockfish < sf.txt
Stockfish 261014 64 by Tord Romstad, Marco Costalba and Joona Kiiski
info nodes 0 time 2
bestmove a7a6 ponder (none)

As you can see, the program exits in 2 ms instead of waiting for the analysis to finish. Has anyone delt with this issue before? Is there a preferred way of interfacing with Stockfish?

1
  • 1
    Did you add a linebreak after "go move 5000"? Sep 1, 2015 at 10:47

4 Answers 4

2

Edit: I think the main problem is that the uci protocol is a dialog. You have to wait for the "readyok" output from the engine before you can issue another command. Probably you just cannot forcefeed all commands in one go.

To quote the uci protocol:

"* all command strings the engine receives will end with '\n', …"

Possibly you just forgot about that in your second line.

4
  • 1
    Thank you! My program seems to have stripped any trailing newlines, so I just added a line to explicitly append one after each command. Sep 1, 2015 at 13:51
  • 2
    Does it work now? Can you actually pipe several commands at once? Sep 1, 2015 at 14:02
  • 1
    It does seem to work, I now write the two commands and newlines to the text file and pipe it all at once; I haven't tested it thoroughly, but it at least works enough to respond to moves and play a full game. Thanks again for your answer. Sep 4, 2015 at 3:05
  • @Emporophobe It doesn't seem to work for me. Could you please give more details as to how were you able to do it? Jun 27, 2020 at 17:04
5

Solution: Use 'expect' script as shown below. Tested with stockfish_8_x64_modern.

BlindKungFuMaster: "I think the main problem is that the uci protocol is a dialog." I agree!

#!/usr/bin/expect

spawn ~/stockfish_8_x64_modern

expect -timeout 1000  Linscott 

send "setoption name Ponder  value false \r isready \r"

expect -timeout 1000  readyok

send "setoption name Hash    value 2048 \r isready \r"

expect -timeout 1000  readyok

send "setoption name Threads value 8    \r isready \r"

expect -timeout 1000  readyok

send "setoption name MultiPV value 4    \r isready \r"

expect -timeout 1000  readyok

set row8 "rnbqkbnr"

set row7 "pppppppp"

set row6 "11111111"

set row5 "11111111"

set row4 "11111111"

set row3 "11111111"

set row2 "PPPPPPPP"

set row1 "RNBQKBNR"


send "position fen $row8/$row7/$row6/$row5/$row4/$row3/$row2/$row1 w KQkq - 0 1 moves e2e4 \r isready \r"

expect -timeout 1000  readyok

send "go infinite \r" 

expect -timeout 999999  readyok
1
  • Can windows batch scripts do the same? to simulate a dialog?
    – dbdb
    Aug 7, 2021 at 1:54
2

look into python-chess package. It includes a protocol for interacting with engines.

1
  • Do you know if it is strict UCI or also the other commands an engine can still take (SF has four of them, mostly for debugging).
    – dbdb
    Aug 7, 2021 at 1:55
1

The problem there is that stockfish process quits as soon as the input stream is closed. And that happens instantaneously, because the input stream is equivalent to a cat command. As a result, Stockfish never gets a chance to run the search tree. So Stockfish just outputs the very first move in it's list (which is a7a6 in your example).

The simple solution is to delay the input stream with a sleep until Stockfish is done with it's analysis. That can be done by using two commands to generate Stockfish's input stream. Example:

( cat sf.txt; sleep 5001; ) | stockfish

That works nice if you know the exact amount of time Stockfish will take, which is 5000 seconds in your example (notice I added 1 second just to be on the safe side).

However, when you are limiting the search by nodes or by depth (such as in go depth 30), you don't know how much time Stockfish will take. In such case, the trick above won't be optimal, as it will either interrupt too early or keep sleeping for too long. So, instead you can use a more elaborated solution, which includes sending Stockfish's output to a file and making the input process wait for the bestmove string to show up on that file:

(
    echo "setoption name Hash value 1024";
    echo "setoption name threads value 10";
    echo "position fen 'rn3rk1/pbppq1pp/1p2pb2/4N2Q/3PN3/3B4/PPP2PPP/R3K2R w KQ - 6 11'";
    echo "go depth 30";
    (grep -m 1 "bestmove" <(tail -f analysis.txt))> /dev/null
) | stockfish | tee /dev/stderr > analysis.txt

Yeah, it is literally catching it's own tail, but it does get to an end. :-)

Explanation:

  • tail -f watches the Stockfish's output file
  • grep -m 1 "bestmove" filters the watched file until that string is found, then quits
  • > /dev/null is to prevent grep's output to be resent to Stockfish
  • | tee /dev/stderr is optional, for you to see Stockfish's output in real time

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.