add_to_group(): gid -> group
[pachi/peepo.git] / gtp.c
blob7b580a1528e505057f94ba34865994295596c950
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 "version.h"
14 void
15 gtp_prefix(char prefix, int id)
17 if (id >= 0)
18 printf("%c%d ", prefix, id);
19 else
20 printf("%c ", prefix);
23 void
24 gtp_output(char prefix, int id, va_list params)
26 gtp_prefix(prefix, id);
27 char *s;
28 while ((s = va_arg(params, char *))) {
29 fputs(s, stdout);
31 putchar('\n'); putchar('\n');
32 fflush(stdout);
35 void
36 gtp_reply(int id, ...)
38 va_list params;
39 va_start(params, id);
40 gtp_output('=', id, params);
41 va_end(params);
44 void
45 gtp_error(int id, ...)
47 va_list params;
48 va_start(params, id);
49 gtp_output('?', id, params);
50 va_end(params);
54 /* XXX: THIS IS TOTALLY INSECURE!!!!
55 * Even basic input checking is missing. */
57 void
58 gtp_parse(struct board *board, struct engine *engine, char *buf)
60 #define next_tok(to_) \
61 to_ = next; \
62 next = next + strcspn(next, " \t\r\n"); \
63 if (*next) { \
64 *next = 0; next++; \
65 next += strspn(next, " \t\r\n"); \
68 if (strchr(buf, '#'))
69 *strchr(buf, '#') = 0;
71 char *cmd, *next = buf;
72 next_tok(cmd);
74 int id = -1;
75 if (isdigit(*cmd)) {
76 id = atoi(cmd);
77 next_tok(cmd);
80 if (!*cmd)
81 return;
83 if (!strcasecmp(cmd, "protocol_version")) {
84 gtp_reply(id, "2", NULL);
86 } else if (!strcasecmp(cmd, "name")) {
87 /* KGS hack */
88 gtp_reply(id, "Pachi ", engine->name, NULL);
90 } else if (!strcasecmp(cmd, "version")) {
91 gtp_reply(id, PACHI_VERSION, ": ", engine->comment, NULL);
93 /* TODO: known_command */
95 } else if (!strcasecmp(cmd, "list_commands")) {
96 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);
98 } else if (!strcasecmp(cmd, "quit")) {
99 gtp_reply(id, NULL);
100 exit(0);
102 } else if (!strcasecmp(cmd, "boardsize")) {
103 char *arg;
104 next_tok(arg);
105 board_resize(board, atoi(arg));
107 gtp_reply(id, NULL);
109 } else if (!strcasecmp(cmd, "clear_board")) {
110 board_clear(board);
111 gtp_reply(id, NULL);
113 } else if (!strcasecmp(cmd, "komi")) {
114 char *arg;
115 next_tok(arg);
116 sscanf(arg, "%f", &board->komi);
118 gtp_reply(id, NULL);
120 } else if (!strcasecmp(cmd, "play")) {
121 struct move m;
123 char *arg;
124 next_tok(arg);
125 m.color = str2stone(arg);
126 next_tok(arg);
127 coord_t *c = str2coord(arg, board_size(board));
128 m.coord = *c; coord_done(c);
130 if (DEBUGL(1))
131 fprintf(stderr, "got move %d,%d,%d\n", m.color, coord_x(m.coord, board), coord_y(m.coord, board));
132 if (board_play(board, &m) < 0) {
133 if (DEBUGL(0)) {
134 fprintf(stderr, "! ILLEGAL MOVE %d,%d,%d\n", m.color, coord_x(m.coord, board), coord_y(m.coord, board));
135 board_print(board, stderr);
137 gtp_error(id, "illegal move", NULL);
138 } else {
139 gtp_reply(id, NULL);
142 } else if (!strcasecmp(cmd, "genmove")) {
143 char *arg;
144 next_tok(arg);
145 enum stone color = str2stone(arg);
146 coord_t *c = engine->genmove(engine, board, color);
147 struct move m = { *c, color };
148 board_play(board, &m);
149 char *str = coord2str(*c, board);
150 if (DEBUGL(1))
151 fprintf(stderr, "playing move %s\n", str);
152 gtp_reply(id, str, NULL);
153 free(str); coord_done(c);
155 } else if (!strcasecmp(cmd, "set_free_handicap")) {
156 struct move m;
157 m.color = S_BLACK;
159 char *arg;
160 next_tok(arg);
161 do {
162 coord_t *c = str2coord(arg, board_size(board));
163 m.coord = *c; coord_done(c);
164 if (DEBUGL(1))
165 fprintf(stderr, "setting handicap %d,%d\n", coord_x(m.coord, board), coord_y(m.coord, board));
167 if (board_play(board, &m) < 0) {
168 if (DEBUGL(0))
169 fprintf(stderr, "! ILLEGAL MOVE %d,%d,%d\n", m.color, coord_x(m.coord, board), coord_y(m.coord, board));
170 gtp_error(id, "illegal move", NULL);
172 next_tok(arg);
173 } while (*arg);
174 gtp_reply(id, NULL);
176 /* TODO: Engine should choose free handicap; however, it tends to take
177 * overly long to think it all out, and unless it's clever its
178 * handicap stones won't be of much help. ;-) */
179 } else if (!strcasecmp(cmd, "place_free_handicap")
180 || !strcasecmp(cmd, "fixed_handicap")) {
181 char *arg;
182 next_tok(arg);
183 int stones = atoi(arg);
185 gtp_prefix('=', id);
186 board_handicap(board, stones, stdout);
187 printf("\n\n"); fflush(stdout);
189 } else if (!strcasecmp(cmd, "final_score")) {
190 float score = board_official_score(board);
191 char str[64];
192 if (DEBUGL(1))
193 fprintf(stderr, "counted score %.1f\n", score);
194 if (score == 0) {
195 gtp_reply(id, "0", NULL);
196 } else if (score > 0) {
197 snprintf(str, 64, "W+%.1f", score);
198 gtp_reply(id, str, NULL);
199 } else {
200 snprintf(str, 64, "B+%.1f", -score);
201 gtp_reply(id, str, NULL);
204 /* XXX: This is a huge hack. */
205 } else if (!strcasecmp(cmd, "final_status_list")) {
206 char *arg;
207 next_tok(arg);
208 assert(!strcasecmp(arg, "dead")); // yes, I know...
209 gtp_reply(id, "", NULL);
211 } else {
212 gtp_error(id, "unknown command", NULL);
215 #undef next_tok