It seems like the list has been busy while I've been on vacation. I'll add my comments as I find time, starting with one of the recent messages. Unfortunately I can't reach Phil's page, getting a 404 like some other people seem to, so I can only comment on the comments to his specification draft.
Anders wrote:
(1) Optional id
What's the purpose of these optional id numbers? As I understand it, the engine is simply echoing them, it can't base any of its decisions on these numbers. So how are they helping the controller program? How are these numbers used in GNU Go, and what would the protocol lose if these were removed from the standard?
Correct, the engine can't and shouldn't try to do anything with those numbers. For the controller they are very useful. I'll give two examples:
1. Regression testing. A regression test suite in GNU Go may look like this:
| loadsgf games/strategy1.sgf | 1 genmove_white | #? [Q13] | | loadsgf games/strategy2.sgf 5 | 2 gg_genmove black | #? [!G2|D2] | | loadsgf games/strategy2.sgf 9 | 3 gg_genmove black | #? [!H1|H2]
This is fed in its entirety (all at once) as GTP input to GNU Go, which gives the response:
| = white | | =1 Q13 | | = black | | =2 C7 | | = black | | =3 F8
Thanks to the id numbers, the regression script can easily identify which responses correspond to which queries. (The lines starting with '#?' are GTP comments which gives information about accepted results to the regression script.)
2. gnugoclient The gnugoclient program has a multithreaded architecture with among others double threads for communication with the go engine, one for reading and one for writing. When some event on the server, e.g. the opponent making a move, prompts a call to the engine, this is handled like this: * Another thread invokes the method SendCommand(command, callback). * A new id number is generated. * The callback is stored in a mapping indexed by the id number. * The id number is prepended to the command and placed in a queue. * The GTP writing thread picks up the request from the queue and sends it to the engine * Sometime later the GTP reading thread picks up the response from the engine. * The id number is extracted from the response. * The callback is retrieved from the mapping where it was stored through the id number. * The callback is invoked with the response from the engine (with id stripped) as argument.
(2) Error messages
Page 5 states that the error message should return "not implemented". So it seems that this error message is standardized, but not others. I'd suggest we standardize a list of error messages, and make them single words, e.g. "not_implemented", "illegal_move", and "invalid_coordinate". Controllers may then be able to make smarter decisions depending on the error message returned.
I doubt the controllers can do very much with other error messages than "unknown command" (this is what GNU Go has always responded and I see no compelling reason to change this to "not implemented") but there is no reason not to standardize the common ones. Would it really simplify matters to use underscore rather than space in the error messages?
(4) Missing commands
- Need a way to set up a position (as discussed previously, playing
moves is not a substitute).
For GNU Go playing moves has worked quite well but I agree we also want a setup command.
- Need to know under what rules the game is being played.
Unless someone has a very good suggestion for precisely how this should be implemented, I'd rather postpone it. For tournament and server use it's no big burden to have to specify this by e.g. command line parameters.
- Need a way to know how much time to spend on a move or on the whole
game, and how much time is left.
Agreed, this is important to include.
- Query position: There should be a way for the controller to get the
current board position from the engine. (Not necessarily a core command, but would help a lot with debugging and verifying engines.)
GNU Go has the color and showboard commands for this purpose.
(5) Argument definitions
- For coordinates, both lowercase and uppercase coordinates should be
acceptable. The standard coordinates are most often given in uppercase, and GTP shouldn't require people to change coordinate notation. (I know, I made that mistake in SGF.)
Absolutely.
- Real: No need for everybody to deal with numbers like 1.7E308. Real
numbers will only be used for things like komi, score, and time left, so a simpler definition will do.
Agreed.
- Date: Why not use the standard YYYY-MM-DD format that's used in SGF?
(Doesn't seem to be used by any commands yet, though.)
I don't know why date should be needed but if there is a need it should absolutely use the YYYY-MM-DD format.
(6) What to do on failure
The GTP standard should clearly state that anytime failure is returned, the state of the Go program must remain unchanged. That simplifies the description of the "On Failure" section for each command, that section simply needs to list the standard error messages that can be returned.
Agreed.
(7) Specific commands
- 'fixed_handicap': What if this command is not sent at the beginning of
the game?
GNU Go currently resets the board before executing the command. It may be better to specify this command to be illegal unless the board is empty.
Is the only purpose of this command to get the coordinates of fixed handicap stones, or does it also play them on the board?
It also plays them on the board.
Why include this in the core set of commands, why not put the responsibility for figuring out where to put handicap stones in the controller?
I think both alternatives are reasonable. The main reason for having this in the engine is that it allows simpler controllers (see e.g. the twogtp program in the GNU Go distribution) and the engine probably needs to know how to place fixed handicap stones anyway if it has some more interface to the world than GTP.
- 'komi': I don't think the standard should specify a default komi. Why
5.5 and not 6.5 or 7.5? The komi should be zero unless specified. I think it will be easier to get all the controllers to always send a komi command than to make sure they remember to set the komi to zero (or 0.5) for handicap games.
In my opinion the GTP standard shouldn't prescribe any default values at all. If the controller expects the engine to play on any specific boardsize or with any specific komi it should tell them.
- 'is_legal': I like this command, but why does it specify color and
coordinate while other commands use separate commands for each color? Why not have 'genmove' and 'move' commands rather than 'genmove_black', 'genmove_white', 'black', and 'white'?
This is only because I happened to implement the 'genmove_*', 'black', and 'white' commands in GNU Go like that a little more than a year ago. As I indicated in an early message to this list I now think this was a mistake and it would be better to have a 'genmove' and 'play' command taking color and color + coordinate as arguments respectively.
(8) State changes
The specification is vague on some points, for example:
- Does 'loadsgf' change boardsize and komi? Does it reset the number of
prisoners?
It should.
- 'boardsize' probably resets the number of prisoners?
This too.
I think explicitly specifying the state maintained by each engine would make it clearer, and would make it easier to implement GTP correctly. For example, board_size, komi, and (optional) number_of_prisoners are clearly part of the state. Apparently, the current player is not (I think it should be, which would simplify many commands, but that's a different matter). Every command affecting this state should specify that.
Agreed, except the comment about current player. Not to include a current player is very intentional to avoid unnecessary limitations on the protocol.
(9) Timeouts
What happens when the controller sends a genmove_black command and then waits for a reply, and waits, and waits, and waits? Should there be a way to query the engine whether it's still thinking?
No. This would be more pain to implement than it's worth. When e.g. GNU Go is thinking about a move it has no mechanism to scan through future GTP commands coming along to check for any possible status queries.
If the controller becomes fed up with the engine's seeming inactivity it should send a 'quit' command and close down the communication.
/Gunnar