Next: , Previous: The Metamachine, Up: GTP


19.5 Adding new GTP commands

The implementation of GTP in GNU Go is distributed over three files, interface/gtp.h, interface/gtp.c, and interface/play_gtp.c. The first two implement a small library of helper functions which can be used also by other programs. In the interest of promoting the GTP they are licensed with minimal restrictions (see GTP License). The actual GTP commands are implemented in play_gtp.c, which has knowledge about the engine internals.

To see how a simple but fairly typical command is implemented we look at gtp_countlib() (a GNU Go private extension command):

     static int
     gtp_countlib(char *s)
     {
       int i, j;
       if (!gtp_decode_coord(s, &i, &j))
         return gtp_failure("invalid coordinate");
     
       if (BOARD(i, j) == EMPTY)
         return gtp_failure("vertex must not be empty");
     
       return gtp_success("%d", countlib(POS(i, j)));
     }

The arguments to the command are passed in the string s. In this case we expect a vertex as argument and thus try to read it with gtp_decode_coord() from gtp.c.

A correctly formatted response should start with either `=' or `?', followed by the identity number (if one was sent), the actual result, and finally two consecutive newlines. It is important to get this formatting correct since the controller in the other end relies on it. Naturally the result itself cannot contain two consecutive newlines but it may be split over several lines by single newlines.

The easiest way to generate a correctly formatted response is with one of the functions gtp_failure() and gtp_success(), assuming that their formatted output does not end with a newline.

Sometimes the output is too complex for use with gtp_success, e.g. if we want to print vertices, which gtp_success() does not support. Then we have to fall back to the construction in e.g. gtp_genmove():

     static int
     gtp_genmove(char *s)
     {
       [...]
       gtp_start_response(GTP_SUCCESS);
       gtp_print_vertex(i, j);
       return gtp_finish_response();
     }

Here gtp_start_response() writes the equal sign and the identity number while gtp_finish_response() adds the final two newlines. The next example is from gtp_list_commands():

     static int
     gtp_list_commands(char *s)
     {
       int k;
       UNUSED(s);
     
       gtp_start_response(GTP_SUCCESS);
     
       for (k = 0; commands[k].name != NULL; k++)
         gtp_printf("%s\n", commands[k].name);
     
       gtp_printf("\n");
       return GTP_OK;
     }

As we have said, the response should be finished with two newlines. Here we have to finish up the response ourselves since we already have one newline in place from the last command printed in the loop.

In order to add a new GTP command to GNU Go, the following pieces of code need to be inserted in play_gtp.c:

  1. A function declaration using the DECLARE macro in the list starting at line 68.
  2. An entry in the commands[] array starting at line 200.
  3. An implementation of the function handling the command.

Useful helper functions in gtp.c/gtp.h are: