Merge branch 'master' of ssh://repo.or.cz/srv/git/pachi
[pachi/json.git] / gtp.c
blobd15f8b1cc943f5252b346c1c9f49c9f188d8272a
1 #define DEBUG
2 #include <assert.h>
3 #include <ctype.h>
4 #include <stdarg.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
9 #include "board.h"
10 #include "debug.h"
11 #include "engine.h"
12 #include "gtp.h"
13 #include "uct/uct.h"
14 #include "version.h"
16 void
17 gtp_prefix(char prefix, int id)
19 if (id >= 0)
20 printf("%c%d ", prefix, id);
21 else
22 printf("%c ", prefix);
25 void
26 gtp_output(char prefix, int id, va_list params)
28 gtp_prefix(prefix, id);
29 char *s;
30 while ((s = va_arg(params, char *))) {
31 fputs(s, stdout);
33 putchar('\n'); putchar('\n');
34 fflush(stdout);
37 void
38 gtp_reply(int id, ...)
40 va_list params;
41 va_start(params, id);
42 gtp_output('=', id, params);
43 va_end(params);
46 void
47 gtp_error(int id, ...)
49 va_list params;
50 va_start(params, id);
51 gtp_output('?', id, params);
52 va_end(params);
56 /* XXX: THIS IS TOTALLY INSECURE!!!!
57 * Even basic input checking is missing. */
59 void
60 gtp_parse(struct board *board, struct engine *engine, char *buf)
62 #define next_tok(to_) \
63 to_ = next; \
64 next = next + strcspn(next, " \t\r\n"); \
65 if (*next) { \
66 *next = 0; next++; \
67 next += strspn(next, " \t\r\n"); \
70 if (strchr(buf, '#'))
71 *strchr(buf, '#') = 0;
73 char *cmd, *next = buf;
74 next_tok(cmd);
76 int id = -1;
77 if (isdigit(*cmd)) {
78 id = atoi(cmd);
79 next_tok(cmd);
82 if (!*cmd)
83 return;
85 if (!strcasecmp(cmd, "protocol_version")) {
86 gtp_reply(id, "2", NULL);
88 } else if (!strcasecmp(cmd, "name")) {
89 /* KGS hack */
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")) {
101 gtp_reply(id, NULL);
102 exit(0);
104 } else if (!strcasecmp(cmd, "boardsize")) {
105 char *arg;
106 next_tok(arg);
107 board_resize(board, atoi(arg));
109 gtp_reply(id, NULL);
111 } else if (!strcasecmp(cmd, "clear_board")) {
112 board_clear(board);
113 if (DEBUGL(1))
114 board_print(board, stderr);
115 gtp_reply(id, NULL);
117 } else if (!strcasecmp(cmd, "komi")) {
118 char *arg;
119 next_tok(arg);
120 sscanf(arg, "%f", &board->komi);
122 if (DEBUGL(1))
123 board_print(board, stderr);
124 gtp_reply(id, NULL);
126 } else if (!strcasecmp(cmd, "play")) {
127 struct move m;
129 char *arg;
130 next_tok(arg);
131 m.color = str2stone(arg);
132 next_tok(arg);
133 coord_t *c = str2coord(arg, board_size(board));
134 m.coord = *c; coord_done(c);
136 if (DEBUGL(1))
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) {
140 if (DEBUGL(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);
145 } else {
146 if (DEBUGL(1))
147 board_print(board, stderr);
148 gtp_reply(id, NULL);
151 } else if (!strcasecmp(cmd, "genmove")) {
152 char *arg;
153 next_tok(arg);
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);
159 if (DEBUGL(1))
160 fprintf(stderr, "playing move %s\n", str);
161 if (DEBUGL(1))
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")) {
167 struct move m;
168 m.color = S_BLACK;
170 char *arg;
171 next_tok(arg);
172 do {
173 coord_t *c = str2coord(arg, board_size(board));
174 m.coord = *c; coord_done(c);
175 if (DEBUGL(1))
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) {
179 if (DEBUGL(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);
183 board->handicap++;
184 next_tok(arg);
185 } while (*arg);
186 if (DEBUGL(1))
187 board_print(board, stderr);
188 gtp_reply(id, NULL);
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")) {
195 char *arg;
196 next_tok(arg);
197 int stones = atoi(arg);
199 gtp_prefix('=', id);
200 board_handicap(board, stones, stdout);
201 if (DEBUGL(1))
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);
207 char str[64];
208 if (DEBUGL(1))
209 fprintf(stderr, "counted score %.1f\n", score);
210 if (score == 0) {
211 gtp_reply(id, "0", NULL);
212 } else if (score > 0) {
213 snprintf(str, 64, "W+%.1f", score);
214 gtp_reply(id, str, NULL);
215 } else {
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")) {
222 char *arg;
223 next_tok(arg);
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'. */
231 char *arg;
232 next_tok(arg);
233 enum stone color = str2stone(arg);
234 if (uct_genbook(engine, board, color))
235 gtp_reply(id, NULL);
236 else
237 gtp_error(id, "error generating book", NULL);
239 } else if (!strcasecmp(cmd, "uct_dumpbook")) {
240 char *arg;
241 next_tok(arg);
242 enum stone color = str2stone(arg);
243 uct_dumpbook(engine, board, color);
244 gtp_reply(id, NULL);
246 } else {
247 gtp_error(id, "unknown command", NULL);
250 #undef next_tok