13 gtp_prefix(char prefix
, int id
)
16 printf("%c%d ", prefix
, id
);
18 printf("%c ", prefix
);
22 gtp_output(char prefix
, int id
, va_list params
)
24 gtp_prefix(prefix
, id
);
26 while ((s
= va_arg(params
, char *))) {
29 putchar('\n'); putchar('\n');
34 gtp_reply(int id
, ...)
38 gtp_output('=', id
, params
);
43 gtp_error(int id
, ...)
47 gtp_output('?', id
, params
);
52 /* XXX: THIS IS TOTALLY INSECURE!!!!
53 * Even basic input checking is missing. */
56 gtp_parse(struct board
*board
, struct engine
*engine
, char *buf
)
58 #define next_tok(to_) \
60 next = next + strcspn(next, " \t\r\n"); \
63 next += strspn(next, " \t\r\n"); \
67 *strchr(buf
, '#') = 0;
69 char *cmd
, *next
= buf
;
81 if (!strcasecmp(cmd
, "protocol_version")) {
82 gtp_reply(id
, "2", NULL
);
84 } else if (!strcasecmp(cmd
, "name")) {
86 gtp_reply(id
, "ZZGo ", engine
->name
, ": ", engine
->comment
, NULL
);
88 } else if (!strcasecmp(cmd
, "version")) {
91 /* TODO: known_command */
93 } else if (!strcasecmp(cmd
, "list_commands")) {
94 gtp_reply(id
, "protocol_version\nname\nversion\nlist_commands\nquit\nboardsize\nclear_board\nkomi\nplay\ngenmove\nset_free_handicap\nplace_free_handicap", NULL
);
96 } else if (!strcasecmp(cmd
, "quit")) {
100 } else if (!strcasecmp(cmd
, "boardsize")) {
103 board_resize(board
, atoi(arg
));
107 } else if (!strcasecmp(cmd
, "clear_board")) {
111 } else if (!strcasecmp(cmd
, "komi")) {
114 sscanf(arg
, "%f", &board
->komi
);
118 } else if (!strcasecmp(cmd
, "play")) {
123 m
.color
= str2stone(arg
);
125 coord_t
*c
= str2coord(arg
, board
->size
);
126 m
.coord
= *c
; coord_done(c
);
129 fprintf(stderr
, "got move %d,%d,%d\n", m
.color
, coord_x(m
.coord
, board
), coord_y(m
.coord
, board
));
130 if (board_play(board
, &m
) < 0) {
132 fprintf(stderr
, "! ILLEGAL MOVE %d,%d,%d\n", m
.color
, coord_x(m
.coord
, board
), coord_y(m
.coord
, board
));
133 gtp_error(id
, "illegal move", NULL
);
138 } else if (!strcasecmp(cmd
, "genmove")) {
141 enum stone color
= str2stone(arg
);
142 coord_t
*c
= engine
->genmove(engine
, board
, color
);
143 struct move m
= { *c
, color
};
144 board_play(board
, &m
);
145 char *str
= coord2str(*c
, board
);
147 fprintf(stderr
, "playing move %s\n", str
);
148 gtp_reply(id
, str
, NULL
);
149 free(str
); coord_done(c
);
151 } else if (!strcasecmp(cmd
, "set_free_handicap")) {
158 coord_t
*c
= str2coord(arg
, board
->size
);
159 m
.coord
= *c
; coord_done(c
);
161 fprintf(stderr
, "setting handicap %d,%d\n", coord_x(m
.coord
, board
), coord_y(m
.coord
, board
));
163 if (board_play(board
, &m
) < 0) {
165 fprintf(stderr
, "! ILLEGAL MOVE %d,%d,%d\n", m
.color
, coord_x(m
.coord
, board
), coord_y(m
.coord
, board
));
166 gtp_error(id
, "illegal move", NULL
);
172 /* TODO: Engine should choose free handicap; however, it tends to take
173 * overly long to think it all out, and unless it's clever its
174 * handicap stones won't be of much help. ;-) */
175 } else if (!strcasecmp(cmd
, "place_free_handicap")
176 || !strcasecmp(cmd
, "fixed_handicap")) {
179 int stones
= atoi(arg
);
182 board_handicap(board
, stones
, stdout
);
183 printf("\n\n"); fflush(stdout
);
185 } else if (!strcasecmp(cmd
, "final_score")) {
186 float score
= board_official_score(board
);
189 fprintf(stderr
, "counted score %.1f\n", score
);
191 gtp_reply(id
, "0", NULL
);
192 } else if (score
> 0) {
193 snprintf(str
, 64, "W+%.1f", score
);
194 gtp_reply(id
, str
, NULL
);
196 snprintf(str
, 64, "B+%.1f", -score
);
197 gtp_reply(id
, str
, NULL
);
201 gtp_error(id
, "unknown command", NULL
);