board_symmetry.type: Note
[pachi.git] / gtp.c
blob8eed8e1b6feca06c8c870fb695cee2d96725e36d
1 #include <assert.h>
2 #include <ctype.h>
3 #include <stdarg.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
8 #include "board.h"
9 #include "debug.h"
10 #include "engine.h"
11 #include "gtp.h"
12 #include "uct/uct.h"
13 #include "version.h"
15 void
16 gtp_prefix(char prefix, int id)
18 if (id >= 0)
19 printf("%c%d ", prefix, id);
20 else
21 printf("%c ", prefix);
24 void
25 gtp_output(char prefix, int id, va_list params)
27 gtp_prefix(prefix, id);
28 char *s;
29 while ((s = va_arg(params, char *))) {
30 fputs(s, stdout);
32 putchar('\n'); putchar('\n');
33 fflush(stdout);
36 void
37 gtp_reply(int id, ...)
39 va_list params;
40 va_start(params, id);
41 gtp_output('=', id, params);
42 va_end(params);
45 void
46 gtp_error(int id, ...)
48 va_list params;
49 va_start(params, id);
50 gtp_output('?', id, params);
51 va_end(params);
55 /* XXX: THIS IS TOTALLY INSECURE!!!!
56 * Even basic input checking is missing. */
58 void
59 gtp_parse(struct board *board, struct engine *engine, char *buf)
61 #define next_tok(to_) \
62 to_ = next; \
63 next = next + strcspn(next, " \t\r\n"); \
64 if (*next) { \
65 *next = 0; next++; \
66 next += strspn(next, " \t\r\n"); \
69 if (strchr(buf, '#'))
70 *strchr(buf, '#') = 0;
72 char *cmd, *next = buf;
73 next_tok(cmd);
75 int id = -1;
76 if (isdigit(*cmd)) {
77 id = atoi(cmd);
78 next_tok(cmd);
81 if (!*cmd)
82 return;
84 if (!strcasecmp(cmd, "protocol_version")) {
85 gtp_reply(id, "2", NULL);
87 } else if (!strcasecmp(cmd, "name")) {
88 /* KGS hack */
89 gtp_reply(id, "Pachi ", engine->name, NULL);
91 } else if (!strcasecmp(cmd, "version")) {
92 gtp_reply(id, PACHI_VERSION, ": ", engine->comment, NULL);
94 /* TODO: known_command */
96 } else if (!strcasecmp(cmd, "list_commands")) {
97 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);
99 } else if (!strcasecmp(cmd, "quit")) {
100 gtp_reply(id, NULL);
101 exit(0);
103 } else if (!strcasecmp(cmd, "boardsize")) {
104 char *arg;
105 next_tok(arg);
106 board_resize(board, atoi(arg));
108 gtp_reply(id, NULL);
110 } else if (!strcasecmp(cmd, "clear_board")) {
111 board_clear(board);
112 gtp_reply(id, NULL);
114 } else if (!strcasecmp(cmd, "komi")) {
115 char *arg;
116 next_tok(arg);
117 sscanf(arg, "%f", &board->komi);
119 gtp_reply(id, NULL);
121 } else if (!strcasecmp(cmd, "play")) {
122 struct move m;
124 char *arg;
125 next_tok(arg);
126 m.color = str2stone(arg);
127 next_tok(arg);
128 coord_t *c = str2coord(arg, board_size(board));
129 m.coord = *c; coord_done(c);
131 if (DEBUGL(1))
132 fprintf(stderr, "got move %d,%d,%d\n", m.color, coord_x(m.coord, board), coord_y(m.coord, board));
133 if (board_play(board, &m) < 0) {
134 if (DEBUGL(0)) {
135 fprintf(stderr, "! ILLEGAL MOVE %d,%d,%d\n", m.color, coord_x(m.coord, board), coord_y(m.coord, board));
136 board_print(board, stderr);
138 gtp_error(id, "illegal move", NULL);
139 } else {
140 gtp_reply(id, NULL);
143 } else if (!strcasecmp(cmd, "genmove")) {
144 char *arg;
145 next_tok(arg);
146 enum stone color = str2stone(arg);
147 coord_t *c = engine->genmove(engine, board, color);
148 struct move m = { *c, color };
149 board_play(board, &m);
150 char *str = coord2str(*c, board);
151 if (DEBUGL(1))
152 fprintf(stderr, "playing move %s\n", str);
153 gtp_reply(id, str, NULL);
154 free(str); coord_done(c);
156 } else if (!strcasecmp(cmd, "set_free_handicap")) {
157 struct move m;
158 m.color = S_BLACK;
160 char *arg;
161 next_tok(arg);
162 do {
163 coord_t *c = str2coord(arg, board_size(board));
164 m.coord = *c; coord_done(c);
165 if (DEBUGL(1))
166 fprintf(stderr, "setting handicap %d,%d\n", coord_x(m.coord, board), coord_y(m.coord, board));
168 if (board_play(board, &m) < 0) {
169 if (DEBUGL(0))
170 fprintf(stderr, "! ILLEGAL MOVE %d,%d,%d\n", m.color, coord_x(m.coord, board), coord_y(m.coord, board));
171 gtp_error(id, "illegal move", NULL);
173 next_tok(arg);
174 } while (*arg);
175 gtp_reply(id, NULL);
177 /* TODO: Engine should choose free handicap; however, it tends to take
178 * overly long to think it all out, and unless it's clever its
179 * handicap stones won't be of much help. ;-) */
180 } else if (!strcasecmp(cmd, "place_free_handicap")
181 || !strcasecmp(cmd, "fixed_handicap")) {
182 char *arg;
183 next_tok(arg);
184 int stones = atoi(arg);
186 gtp_prefix('=', id);
187 board_handicap(board, stones, stdout);
188 printf("\n\n"); fflush(stdout);
190 } else if (!strcasecmp(cmd, "final_score")) {
191 float score = board_official_score(board);
192 char str[64];
193 if (DEBUGL(1))
194 fprintf(stderr, "counted score %.1f\n", score);
195 if (score == 0) {
196 gtp_reply(id, "0", NULL);
197 } else if (score > 0) {
198 snprintf(str, 64, "W+%.1f", score);
199 gtp_reply(id, str, NULL);
200 } else {
201 snprintf(str, 64, "B+%.1f", -score);
202 gtp_reply(id, str, NULL);
205 /* XXX: This is a huge hack. */
206 } else if (!strcasecmp(cmd, "final_status_list")) {
207 char *arg;
208 next_tok(arg);
209 assert(!strcasecmp(arg, "dead")); // yes, I know...
210 gtp_reply(id, "", NULL);
212 /* Custom commands for handling UCT opening book */
213 } else if (!strcasecmp(cmd, "uct_genbook")) {
214 /* Board must be initialized properly, as if for genmove;
215 * makes sense only as 'uct_genbook b'. */
216 char *arg;
217 next_tok(arg);
218 enum stone color = str2stone(arg);
219 if (uct_genbook(engine, board, color))
220 gtp_reply(id, NULL);
221 else
222 gtp_error(id, "error generating book", NULL);
224 } else if (!strcasecmp(cmd, "uct_dumpbook")) {
225 char *arg;
226 next_tok(arg);
227 enum stone color = str2stone(arg);
228 uct_dumpbook(engine, board, color);
229 gtp_reply(id, NULL);
231 } else {
232 gtp_error(id, "unknown command", NULL);
235 #undef next_tok