Paul wrote (on the computer-go list):
> About asynchronous move generation.
>
> I'd propose something like this. Add some form for asynchronous
> responses. E.g. '=[id] ...' means success, '?[id] ...' means error
> (this is as now) and '%[id] ...' means asynchronous response. Maybe
> for asynchronous commands it makes sense to make id mandatory.
> Responses must not be mixed, i.e. you cannot start a synchronous
> response inside asynchronous or vice versa (else they will be
> impossible to parse properly.)
This is in the same direction I've been thinking. To make it consistent
with GTP version 2 and fully backwards compatible it can be designed
like this:
* Asynchronous responses from the engine are encoded like Paul proposes
but with "!" as first character (there is precedence in a protocol GTP
was originally inspired by). Naturally one response must be complete
before starting on another, whether synchronous or asynchronous.
* Asynchronous messages may only be sent as responses to asynchronous
commands. Thus a GTP version 2 controller would never become confused
by asynchronous responses it knows nothing about since it would only
send synchronous commands.
* Asynchronous responses have the same id as the command initiating
them. The id may as usual be omitted by the controller if it is
confident that it don't need it.
* An asynchronous command must first be acknowledged by a synchronous
response (would usually be an empty response if there are no problems
and otherwise an error response).
* An asynchronous command may additionally have zero, one, or multiple
asynchronous responses, depending on the nature of the command and the
situation. For example an asynchronous genmove command would normally
have one asynchronous response, but zero if the command is aborted. A
command requesting debug output could produce any number of
asynchronous responses.
* Whether an engine is capable of doing asynchronous responses can as
usual be tested by known_command or list_commands to see whether it
supports specific (asynchronous) commands.
* The asynchronous genmove command would be named async_genmove. In
contrast to the normal genmove command it would only generate a move,
not actually play it. (To keep sanity and avoid undos when the
ordering of move generation and abort command depends on race
conditions.)
* To abort the asynchronous genmove, the controller should send the
(synchronous) command abort_async_genmove. If the engine has not
returned the asynchronous genmove response before responding to the
abort command, it is no longer allowed to return a move. I'm open for
discussion on the exact name and whether it should return an error if
the move had already been sent (I don't think it should).
Example 1: Asynchronous genmove with an intervening synchronous command.
Command 3 is sent after receiving the asynchronous move.
Controller:
1 async_genmove black
2 version
3 play black E5
Engine:
=1
=2 4.0
!1 E5
=3
Example 2: Asynchronous genmove, aborted. The controller plays an own
move instead.
Controller:
1 async_genmove black
2 abort_async_genmove
3 play black C3
Engine:
=1
=2
=3
Example 2b (BAD): Like example 2, but the engine makes an incorrect
response.
Controller:
1 async_genmove black
2 abort_async_genmove
3 play black C3
Engine:
=1
=2
!1 E5
=3
Example 3: Like example 2, but abort command comes too late.
Controller:
1 async_genmove black
2 abort_async_genmove
3 play black C3
Engine:
=1
!1 E5
=2
=3
Example 4: Asynchronous genmove sent to an engine not supporting it.
Controller:
1 async_genmove black
Engine:
?1 unknown command
/Gunnar