17 gtp_prefix(char prefix
, int id
)
20 printf("%c%d ", prefix
, id
);
22 printf("%c ", prefix
);
26 gtp_output(char prefix
, int id
, va_list params
)
28 gtp_prefix(prefix
, id
);
30 while ((s
= va_arg(params
, char *))) {
33 putchar('\n'); putchar('\n');
38 gtp_reply(int id
, ...)
42 gtp_output('=', id
, params
);
47 gtp_error(int id
, ...)
51 gtp_output('?', id
, params
);
56 /* XXX: THIS IS TOTALLY INSECURE!!!!
57 * Even basic input checking is missing. */
60 gtp_parse(struct board
*board
, struct engine
*engine
, char *buf
)
62 #define next_tok(to_) \
64 next = next + strcspn(next, " \t\r\n"); \
67 next += strspn(next, " \t\r\n"); \
71 *strchr(buf
, '#') = 0;
73 char *cmd
, *next
= buf
;
85 if (!strcasecmp(cmd
, "protocol_version")) {
86 gtp_reply(id
, "2", NULL
);
88 } else if (!strcasecmp(cmd
, "name")) {
90 gtp_reply(id
, "Pachi ", engine
->name
, NULL
);
92 } else if (!strcasecmp(cmd
, "version")) {
93 gtp_reply(id
, PACHI_VERSION
, ": ", engine
->comment
, NULL
);
95 /* TODO: known_command */
97 } else if (!strcasecmp(cmd
, "list_commands")) {
98 gtp_reply(id
, "protocol_version\nname\nversion\nlist_commands\nquit\nboardsize\nclear_board\nkomi\nplay\ngenmove\nset_free_handicap\nplace_free_handicap\nfinal_status_list", NULL
);
100 } else if (!strcasecmp(cmd
, "quit")) {
104 } else if (!strcasecmp(cmd
, "boardsize")) {
107 board_resize(board
, atoi(arg
));
111 } else if (!strcasecmp(cmd
, "clear_board")) {
114 board_print(board
, stderr
);
117 } else if (!strcasecmp(cmd
, "komi")) {
120 sscanf(arg
, "%f", &board
->komi
);
123 board_print(board
, stderr
);
126 } else if (!strcasecmp(cmd
, "play")) {
131 m
.color
= str2stone(arg
);
133 coord_t
*c
= str2coord(arg
, board_size(board
));
134 m
.coord
= *c
; coord_done(c
);
137 fprintf(stderr
, "got move %d,%d,%d\n", m
.color
, coord_x(m
.coord
, board
), coord_y(m
.coord
, board
));
138 engine
->notify_play(engine
, board
, &m
);
139 if (board_play(board
, &m
) < 0) {
141 fprintf(stderr
, "! ILLEGAL MOVE %d,%d,%d\n", m
.color
, coord_x(m
.coord
, board
), coord_y(m
.coord
, board
));
142 board_print(board
, stderr
);
144 gtp_error(id
, "illegal move", NULL
);
147 board_print(board
, stderr
);
151 } else if (!strcasecmp(cmd
, "genmove")) {
154 enum stone color
= str2stone(arg
);
155 coord_t
*c
= engine
->genmove(engine
, board
, color
);
156 struct move m
= { *c
, color
};
157 board_play(board
, &m
);
158 char *str
= coord2str(*c
, board
);
160 fprintf(stderr
, "playing move %s\n", str
);
162 board_print(board
, stderr
);
163 gtp_reply(id
, str
, NULL
);
164 free(str
); coord_done(c
);
166 } else if (!strcasecmp(cmd
, "set_free_handicap")) {
173 coord_t
*c
= str2coord(arg
, board_size(board
));
174 m
.coord
= *c
; coord_done(c
);
176 fprintf(stderr
, "setting handicap %d,%d\n", coord_x(m
.coord
, board
), coord_y(m
.coord
, board
));
178 if (board_play(board
, &m
) < 0) {
180 fprintf(stderr
, "! ILLEGAL MOVE %d,%d,%d\n", m
.color
, coord_x(m
.coord
, board
), coord_y(m
.coord
, board
));
181 gtp_error(id
, "illegal move", NULL
);
187 board_print(board
, stderr
);
190 /* TODO: Engine should choose free handicap; however, it tends to take
191 * overly long to think it all out, and unless it's clever its
192 * handicap stones won't be of much help. ;-) */
193 } else if (!strcasecmp(cmd
, "place_free_handicap")
194 || !strcasecmp(cmd
, "fixed_handicap")) {
197 int stones
= atoi(arg
);
200 board_handicap(board
, stones
, stdout
);
202 board_print(board
, stderr
);
203 printf("\n\n"); fflush(stdout
);
205 } else if (!strcasecmp(cmd
, "final_score")) {
206 float score
= board_official_score(board
);
209 fprintf(stderr
, "counted score %.1f\n", score
);
211 gtp_reply(id
, "0", NULL
);
212 } else if (score
> 0) {
213 snprintf(str
, 64, "W+%.1f", score
);
214 gtp_reply(id
, str
, NULL
);
216 snprintf(str
, 64, "B+%.1f", -score
);
217 gtp_reply(id
, str
, NULL
);
220 /* XXX: This is a huge hack. */
221 } else if (!strcasecmp(cmd
, "final_status_list")) {
224 assert(!strcasecmp(arg
, "dead")); // yes, I know...
225 gtp_reply(id
, "", NULL
);
227 /* Custom commands for handling UCT opening book */
228 } else if (!strcasecmp(cmd
, "uct_genbook")) {
229 /* Board must be initialized properly, as if for genmove;
230 * makes sense only as 'uct_genbook b'. */
233 enum stone color
= str2stone(arg
);
234 if (uct_genbook(engine
, board
, color
))
237 gtp_error(id
, "error generating book", NULL
);
239 } else if (!strcasecmp(cmd
, "uct_dumpbook")) {
242 enum stone color
= str2stone(arg
);
243 uct_dumpbook(engine
, board
, color
);
247 gtp_error(id
, "unknown command", NULL
);