Piping input into an engine

Discussion of chess software programming and technical issues.

Moderator: Ras

gflohr
Posts: 57
Joined: Fri Jul 23, 2021 5:24 pm
Location: Elin Pelin
Full name: Guido Flohr

Piping input into an engine

Post by gflohr »

An engine should still be responsive while searching, and therefore things like "echo go depth 5 | ./myengine" usually don't work, because the first time that the engine interrupts the search for checking input it will get an eof and terminate.

This is good, when you want the engine to be responsive even while thinking but bad if you want to script your engine. I currently have two ideas to mitigate that problem. I could write a little filter that knows which uci commands expect an engine reply and which one's don't or I can implement a custom command "batch on/off" into my engine controlling whether input should interrupt a search or not.

Has that been discussed before? Is there something like a standard solution to it? Using cutechess-cli for such a simple task looks a little bit like of overkill to me.
BrokenKeyboard
Posts: 24
Joined: Tue Mar 16, 2021 11:11 pm
Full name: Het Satasiya

Re: Piping input into an engine

Post by BrokenKeyboard »

You could just use the < operator in bash (which i assume your using).
./myengine < commands.txt
This doesnt allow you to do timings, but it does simulate stdin and you can pipe stdout to a file if you wish.
gflohr
Posts: 57
Joined: Fri Jul 23, 2021 5:24 pm
Location: Elin Pelin
Full name: Guido Flohr

Re: Piping input into an engine

Post by gflohr »

I know how to redirect input and output. But a properly written engine will terminate the search and the program itself as soon as it sees EOF. Try "echo go | stockfish" and it will just print its greeting and then "bestmove a2a3" because this is the first move that the move generator produces.
User avatar
mvanthoor
Posts: 1784
Joined: Wed Jul 03, 2019 4:42 pm
Location: Netherlands
Full name: Marcel Vanthoor

Re: Piping input into an engine

Post by mvanthoor »

gflohr wrote: Tue Sep 28, 2021 9:11 am I know how to redirect input and output. But a properly written engine will terminate the search and the program itself as soon as it sees EOF. Try "echo go | stockfish" and it will just print its greeting and then "bestmove a2a3" because this is the first move that the move generator produces.
Why? That's a choice. My engine only stops the search if it receives the "stop" and "quit" commands (and in my case, "exit", because I type that half of the time). When I perform your test, the engine keeps searching and searching; you can never quit by typing a command however, because input doesn't come from stdin anymore.

Maybe the proper way _is_ to quit on EOF; if so, I'll have to add that some day.
Author of Rustic, an engine written in Rust.
Releases | Code | Docs | Progress | CCRL
gflohr
Posts: 57
Joined: Fri Jul 23, 2021 5:24 pm
Location: Elin Pelin
Full name: Guido Flohr

Re: Piping input into an engine

Post by gflohr »

My engine treats almost every valid input as an implicit stop. IMHO that is more user-friendly. You can just type "go ..." start a new search.

I think you are well advised to terminate on EOF. Imagine you are currently in an "go infinite" search and the user closes the window.
gflohr
Posts: 57
Joined: Fri Jul 23, 2021 5:24 pm
Location: Elin Pelin
Full name: Guido Flohr

Re: Piping input into an engine

Post by gflohr »

Back to the original question: I have now implemented an option "Batch" with default false. When set to true, the engine does not check input during the search, so that all commands are processed sequentially. I think that this is a reasonable extension.
User avatar
Ras
Posts: 2703
Joined: Tue Aug 30, 2016 8:19 pm
Full name: Rasmus Althoff

Re: Piping input into an engine

Post by Ras »

mvanthoor wrote: Tue Sep 28, 2021 11:54 amMaybe the proper way _is_ to quit on EOF
It is. If the GUI exits unexpectedly, you don't want your engine process to linger around.
Rasmus Althoff
https://www.ct800.net
User avatar
mvanthoor
Posts: 1784
Joined: Wed Jul 03, 2019 4:42 pm
Location: Netherlands
Full name: Marcel Vanthoor

Re: Piping input into an engine

Post by mvanthoor »

Ras wrote: Tue Sep 28, 2021 3:58 pm
mvanthoor wrote: Tue Sep 28, 2021 11:54 amMaybe the proper way _is_ to quit on EOF
It is. If the GUI exits unexpectedly, you don't want your engine process to linger around.
OK. When I did "echo go | ./rustic", the engine would start a "go infinite", and be unable to terminate because input is not coming from stdin. I added terminating on reading 0 bytes (EOF), and if I now try the same thing, the engine starts but immediately exits. The termination command follows "go" so quickly that all threads terminate even before the move generator has a chance to output anything. As using a chess engine in this way is a super-niche case, I'm going to leave it at that.

To OP and Ras: thanks for pointing out that terminating on EOF should be standard behavior.
Author of Rustic, an engine written in Rust.
Releases | Code | Docs | Progress | CCRL
gflohr
Posts: 57
Joined: Fri Jul 23, 2021 5:24 pm
Location: Elin Pelin
Full name: Guido Flohr

Re: Piping input into an engine

Post by gflohr »

mvanthoor wrote: Tue Sep 28, 2021 6:57 pm OK. When I did "echo go | ./rustic", the engine would start a "go infinite", and be unable to terminate because input is not coming from stdin. I added terminating on reading 0 bytes (EOF), and if I now try the same thing, the engine starts but immediately exits. The termination command follows "go" so quickly that all threads terminate even before the move generator has a chance to output anything. As using a chess engine in this way is a super-niche case, I'm going to leave it at that.
Well, I'm a unix-guy and for me it is not a super-niche case but rather second nature. If I want to find out what Stockfish's favorite opening move is, I would test that with "echo go depth 80 | stockfish" but that gives me "bestmove a2a3" as a desperate attempt by stockfish to recover from the unexpected EOF with at least any move.

If Stockfish followed my suggestion, I could create this text file:

Code: Select all

uci
setoption name Batch value true
go depth 80
and then pipe it into Stockfish with "stockfish <commands.txt" and it would do what I want. With Stockfish it doesn't work, with Plisco it now does. ;)
User avatar
mvanthoor
Posts: 1784
Joined: Wed Jul 03, 2019 4:42 pm
Location: Netherlands
Full name: Marcel Vanthoor

Re: Piping input into an engine

Post by mvanthoor »

gflohr wrote: Thu Sep 30, 2021 9:57 pm
mvanthoor wrote: Tue Sep 28, 2021 6:57 pm OK. When I did "echo go | ./rustic", the engine would start a "go infinite", and be unable to terminate because input is not coming from stdin. I added terminating on reading 0 bytes (EOF), and if I now try the same thing, the engine starts but immediately exits. The termination command follows "go" so quickly that all threads terminate even before the move generator has a chance to output anything. As using a chess engine in this way is a super-niche case, I'm going to leave it at that.
Well, I'm a unix-guy and for me it is not a super-niche case but rather second nature. If I want to find out what Stockfish's favorite opening move is, I would test that with "echo go depth 80 | stockfish" but that gives me "bestmove a2a3" as a desperate attempt by stockfish to recover from the unexpected EOF with at least any move.

If Stockfish followed my suggestion, I could create this text file:

Code: Select all

uci
setoption name Batch value true
go depth 80
and then pipe it into Stockfish with "stockfish <commands.txt" and it would do what I want. With Stockfish it doesn't work, with Plisco it now does. ;)
I could make it so that the engine sees the EOF and not react to it until the last command has been completely executed, discarding all other commands that may come in. Even though I'm a long-time Linux user myself (and recently fully switched to it on the desktop, finally) who uses the command line extensively, I can't see myself using a chess engine like that.

If I ever need to, I'll change it at that time. For now, Rustic sees the EOF, and the communication thread sends a Quit to the main engine thread, which makes the engine terminate all of its running threads. This happens so fast that the engine doesn't even come up with a move, but it doesn't hang anymore either.
Author of Rustic, an engine written in Rust.
Releases | Code | Docs | Progress | CCRL