Moggy: Move atari check to global_atari_check()
[pachi.git] / gtp.c
blob20682bf68eb1db58dc65573147163b74b3d86e09
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"
13 void
14 gtp_prefix(char prefix, int id)
16 if (id >= 0)
17 printf("%c%d ", prefix, id);
18 else
19 printf("%c ", prefix);
22 void
23 gtp_output(char prefix, int id, va_list params)
25 gtp_prefix(prefix, id);
26 char *s;
27 while ((s = va_arg(params, char *))) {
28 fputs(s, stdout);
30 putchar('\n'); putchar('\n');
31 fflush(stdout);
34 void
35 gtp_reply(int id, ...)
37 va_list params;
38 va_start(params, id);
39 gtp_output('=', id, params);
40 va_end(params);
43 void
44 gtp_error(int id, ...)
46 va_list params;
47 va_start(params, id);
48 gtp_output('?', id, params);
49 va_end(params);
53 /* XXX: THIS IS TOTALLY INSECURE!!!!
54 * Even basic input checking is missing. */
56 void
57 gtp_parse(struct board *board, struct engine *engine, char *buf)
59 #define next_tok(to_) \
60 to_ = next; \
61 next = next + strcspn(next, " \t\r\n"); \
62 if (*next) { \
63 *next = 0; next++; \
64 next += strspn(next, " \t\r\n"); \
67 if (strchr(buf, '#'))
68 *strchr(buf, '#') = 0;
70 char *cmd, *next = buf;
71 next_tok(cmd);
73 int id = -1;
74 if (isdigit(*cmd)) {
75 id = atoi(cmd);
76 next_tok(cmd);
79 if (!*cmd)
80 return;
82 if (!strcasecmp(cmd, "protocol_version")) {
83 gtp_reply(id, "2", NULL);
85 } else if (!strcasecmp(cmd, "name")) {
86 /* KGS hack */
87 gtp_reply(id, "Pachi ", engine->name, ": ", engine->comment, NULL);
89 } else if (!strcasecmp(cmd, "version")) {
90 gtp_reply(id, NULL);
92 /* TODO: known_command */
94 } else if (!strcasecmp(cmd, "list_commands")) {
95 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);
97 } else if (!strcasecmp(cmd, "quit")) {
98 gtp_reply(id, NULL);
99 exit(0);
101 } else if (!strcasecmp(cmd, "boardsize")) {
102 char *arg;
103 next_tok(arg);
104 board_resize(board, atoi(arg));
106 gtp_reply(id, NULL);
108 } else if (!strcasecmp(cmd, "clear_board")) {
109 board_clear(board);
110 gtp_reply(id, NULL);
112 } else if (!strcasecmp(cmd, "komi")) {
113 char *arg;
114 next_tok(arg);
115 sscanf(arg, "%f", &board->komi);
117 gtp_reply(id, NULL);
119 } else if (!strcasecmp(cmd, "play")) {
120 struct move m;
122 char *arg;
123 next_tok(arg);
124 m.color = str2stone(arg);
125 next_tok(arg);
126 coord_t *c = str2coord(arg, board->size);
127 m.coord = *c; coord_done(c);
129 if (DEBUGL(1))
130 fprintf(stderr, "got move %d,%d,%d\n", m.color, coord_x(m.coord, board), coord_y(m.coord, board));
131 if (board_play(board, &m) < 0) {
132 if (DEBUGL(0)) {
133 fprintf(stderr, "! ILLEGAL MOVE %d,%d,%d\n", m.color, coord_x(m.coord, board), coord_y(m.coord, board));
134 board_print(board, stderr);
136 gtp_error(id, "illegal move", NULL);
137 } else {
138 gtp_reply(id, NULL);
141 } else if (!strcasecmp(cmd, "genmove")) {
142 char *arg;
143 next_tok(arg);
144 enum stone color = str2stone(arg);
145 coord_t *c = engine->genmove(engine, board, color);
146 struct move m = { *c, color };
147 board_play(board, &m);
148 char *str = coord2str(*c, board);
149 if (DEBUGL(1))
150 fprintf(stderr, "playing move %s\n", str);
151 gtp_reply(id, str, NULL);
152 free(str); coord_done(c);
154 } else if (!strcasecmp(cmd, "set_free_handicap")) {
155 struct move m;
156 m.color = S_BLACK;
158 char *arg;
159 next_tok(arg);
160 do {
161 coord_t *c = str2coord(arg, board->size);
162 m.coord = *c; coord_done(c);
163 if (DEBUGL(1))
164 fprintf(stderr, "setting handicap %d,%d\n", coord_x(m.coord, board), coord_y(m.coord, board));
166 if (board_play(board, &m) < 0) {
167 if (DEBUGL(0))
168 fprintf(stderr, "! ILLEGAL MOVE %d,%d,%d\n", m.color, coord_x(m.coord, board), coord_y(m.coord, board));
169 gtp_error(id, "illegal move", NULL);
171 next_tok(arg);
172 } while (*arg);
173 gtp_reply(id, NULL);
175 /* TODO: Engine should choose free handicap; however, it tends to take
176 * overly long to think it all out, and unless it's clever its
177 * handicap stones won't be of much help. ;-) */
178 } else if (!strcasecmp(cmd, "place_free_handicap")
179 || !strcasecmp(cmd, "fixed_handicap")) {
180 char *arg;
181 next_tok(arg);
182 int stones = atoi(arg);
184 gtp_prefix('=', id);
185 board_handicap(board, stones, stdout);
186 printf("\n\n"); fflush(stdout);
188 } else if (!strcasecmp(cmd, "final_score")) {
189 float score = board_official_score(board);
190 char str[64];
191 if (DEBUGL(1))
192 fprintf(stderr, "counted score %.1f\n", score);
193 if (score == 0) {
194 gtp_reply(id, "0", NULL);
195 } else if (score > 0) {
196 snprintf(str, 64, "W+%.1f", score);
197 gtp_reply(id, str, NULL);
198 } else {
199 snprintf(str, 64, "B+%.1f", -score);
200 gtp_reply(id, str, NULL);
203 /* XXX: This is a huge hack. */
204 } else if (!strcasecmp(cmd, "final_status_list")) {
205 char *arg;
206 next_tok(arg);
207 assert(!strcasecmp(arg, "dead")); // yes, I know...
208 gtp_reply(id, "", NULL);
210 } else {
211 gtp_error(id, "unknown command", NULL);
214 #undef next_tok