/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* This is GNU Go, a Go program. Contact gnugo@gnu.org, or see *
* http://www.gnu.org/software/gnugo/ for more information. *
* To facilitate development of the Go Text Protocol, the two *
* files gtp.c and gtp.h are licensed under less restrictive *
* terms than the rest of GNU Go. *
* Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 and *
* 2009 by the Free Software Foundation. *
* Permission is hereby granted, free of charge, to any person *
* obtaining a copy of this file gtp.c, to deal in the Software *
* without restriction, including without limitation the rights *
* to use, copy, modify, merge, publish, distribute, and/or *
* sell copies of the Software, and to permit persons to whom *
* the Software is furnished to do so, provided that the above *
* copyright notice(s) and this permission notice appear in all *
* copies of the Software and that both the above copyright *
* notice(s) and this permission notice appear in supporting *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY *
* KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE *
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR *
* PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO *
* EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS *
* NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR *
* CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING *
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF *
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT *
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS *
* Except as contained in this notice, the name of a copyright *
* holder shall not be used in advertising or otherwise to *
* promote the sale, use or other dealings in this Software *
* without prior written authorization of the copyright holder. *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* These are copied from gnugo.h. We don't include this file in order
* to remain as independent as possible of GNU Go internals.
/* We need to keep track of the board size in order to be able to
* convert between coordinate descriptions. We could also have passed
* the board size in all calls needing it, but that would be
* unnecessarily inconvenient.
static int gtp_boardsize
= -1;
/* Vertex transformation hooks. */
static gtp_transform_ptr vertex_transform_input_hook
= NULL
;
static gtp_transform_ptr vertex_transform_output_hook
= NULL
;
/* Current id number. We keep track of this internally rather than
* pass it to the functions processing the commands, since those can't
* do anything useful with it anyway.
/* The file all GTP output goes to. This is made global for the user
* of this file may want to use functions other than gtp_printf() etc.
* Set by gtp_main_loop().
FILE *gtp_output_file
= NULL
;
/* Read filehandle gtp_input linewise and interpret as GTP commands. */
gtp_main_loop(struct gtp_command commands
[],
FILE *gtp_input
, FILE *gtp_output
, FILE *gtp_dump_commands
)
char command
[GTP_BUFSIZE
];
gtp_output_file
= gtp_output
;
while (status
== GTP_OK
) {
/* Read a line from gtp_input. */
if (!fgets(line
, GTP_BUFSIZE
, gtp_input
))
break; /* EOF or some error */
fputs(line
, gtp_dump_commands
);
fflush(gtp_dump_commands
);
/* Preprocess the line. */
for (i
= 0, p
= line
; line
[i
]; i
++) {
/* Convert HT (9) to SPACE (32). */
/* Remove CR (13) and all other control characters except LF (10). */
else if ((c
> 0 && c
<= 9)
/* Keep ordinary text. */
/* Look for an identification number. */
if (sscanf(p
, "%d%n", ¤t_id
, &n
) == 1)
current_id
= -1; /* No identification number. */
/* Look for command name. */
if (sscanf(p
, " %s %n", command
, &n
) < 1)
continue; /* Whitespace only on this line, ignore. */
/* Search the list of commands and call the corresponding function
for (i
= 0; commands
[i
].name
!= NULL
; i
++) {
if (strcmp(command
, commands
[i
].name
) == 0) {
status
= (*commands
[i
].function
)(p
);
if (commands
[i
].name
== NULL
)
gtp_failure("unknown command");
/* Set the board size used in coordinate conversions. */
gtp_internal_set_boardsize(int size
)
/* If you need to transform the coordinates on input or output, use
* these functions to set hook functions which are called any time
* coordinates are read or about to be written. In GNU Go this is used
* to simulate rotated boards in regression tests.
gtp_set_vertex_transform_hooks(gtp_transform_ptr in
, gtp_transform_ptr out
)
vertex_transform_input_hook
= in
;
vertex_transform_output_hook
= out
;
* This function works like printf, except that it only understands
* very few of the standard formats, to be precise %c, %d, %f, %s.
* But it also accepts %m, which takes two integers and writes a vertex,
* and %C, which takes a color value and writes a color string.
gtp_mprintf(const char *fmt
, ...)
/* rules of promotion => passed as int, not char */
putc(c
, gtp_output_file
);
fprintf(gtp_output_file
, "%d", d
);
double f
= va_arg(ap
, double); /* passed as double, not float */
fprintf(gtp_output_file
, "%f", f
);
char *s
= va_arg(ap
, char *);
fputs(s
, gtp_output_file
);
int color
= va_arg(ap
, int);
fputs("white", gtp_output_file
);
fputs("black", gtp_output_file
);
fputs("empty", gtp_output_file
);
/* FIXME: Should go to `stderr' instead? */
fprintf(gtp_output_file
, "\n\nUnknown format character '%c'\n", *fmt
);
putc(*fmt
, gtp_output_file
);
/* This currently works exactly like printf. */
gtp_printf(const char *format
, ...)
vfprintf(gtp_output_file
, format
, ap
);
/* Write success or failure indication plus identity number if one was
gtp_start_response(int status
)
if (status
== GTP_SUCCESS
)
gtp_printf("%d ", current_id
);
/* Finish a GTP response by writing a double newline and returning GTP_OK. */
/* Write a full success response. Except for the id number, the call
* is just like one to printf.
gtp_success(const char *format
, ...)
gtp_start_response(GTP_SUCCESS
);
vfprintf(gtp_output_file
, format
, ap
);
return gtp_finish_response();
/* Write a full failure response. The call is identical to gtp_success. */
gtp_failure(const char *format
, ...)
gtp_start_response(GTP_FAILURE
);
vfprintf(gtp_output_file
, format
, ap
);
return gtp_finish_response();
/* Write a panic message. */
gtp_printf("! panic\n\n");
/* Convert a string describing a color, "b", "black", "w", or "white",
* to GNU Go's integer representation of colors. Return the number of
* characters read from the string s.
gtp_decode_color(char *s
, int *color
)
assert(gtp_boardsize
> 0);
if (sscanf(s
, "%6s%n", color_string
, &n
) != 1)
for (i
= 0; i
< (int) strlen(color_string
); i
++)
color_string
[i
] = tolower((int) color_string
[i
]);
if (strcmp(color_string
, "b") == 0
|| strcmp(color_string
, "black") == 0)
else if (strcmp(color_string
, "w") == 0
|| strcmp(color_string
, "white") == 0)
/* Convert an intersection given by a string to two coordinates
* according to GNU Go's convention. Return the number of characters
* read from the string s.
gtp_decode_coord(char *s
, int *i
, int *j
)
assert(gtp_boardsize
> 0);
if (sscanf(s
, " %c%d%n", &column
, &row
, &n
) != 2)
if (tolower((int) column
) == 'i')
*j
= tolower((int) column
) - 'a';
if (tolower((int) column
) > 'i')
*i
= gtp_boardsize
- row
;
if (*i
< 0 || *i
>= gtp_boardsize
|| *j
< 0 || *j
>= gtp_boardsize
)
if (vertex_transform_input_hook
!= NULL
)
(*vertex_transform_input_hook
)(*i
, *j
, i
, j
);
/* Convert a move, i.e. "b" or "w" followed by a vertex to a color and
* coordinates. Return the number of characters read from the string
* s. The vertex may be "pass" and then the coordinates are set to (-1, -1).
gtp_decode_move(char *s
, int *color
, int *i
, int *j
)
assert(gtp_boardsize
> 0);
n1
= gtp_decode_color(s
, color
);
n2
= gtp_decode_coord(s
+ n1
, i
, j
);
if (sscanf(s
+ n1
, "%5s%n", buf
, &n2
) != 1)
for (k
= 0; k
< (int) strlen(buf
); k
++)
buf
[k
] = tolower((int) buf
[k
]);
if (strcmp(buf
, "pass") != 0)
/* This a bubble sort. Given the expected size of the sets to
* sort, it's probably not worth the overhead to set up a call to
sort_moves(int n
, int movei
[], int movej
[])
for (b
= n
-1; b
> 0; b
--) {
for (a
= 0; a
< b
; a
++) {
|| (movei
[a
] == movei
[b
] && movej
[a
] > movej
[b
])) {
/* Write a number of space separated vertices. The moves are sorted
gtp_print_vertices(int n
, int movei
[], int movej
[])
assert(gtp_boardsize
> 0);
sort_moves(n
, movei
, movej
);
for (k
= 0; k
< n
; k
++) {
if (movei
[k
] == -1 && movej
[k
] == -1)
else if (movei
[k
] < 0 || movei
[k
] >= gtp_boardsize
|| movej
[k
] < 0 || movej
[k
] >= gtp_boardsize
)
if (vertex_transform_output_hook
!= NULL
)
(*vertex_transform_output_hook
)(movei
[k
], movej
[k
], &ri
, &rj
);
gtp_printf("%c%d", 'A' + rj
+ (rj
>= 8), gtp_boardsize
- ri
);
/* Write a single move. */
gtp_print_vertex(int i
, int j
)
gtp_print_vertices(1, &i
, &j
);