simple-gtp.c
Raw
1#include <simple-go/simple-gtp.h>
2
3typedef struct msg_formatted
4{
5 char* command;
6 Vector* arguments;
7 char* id;
8} msg_formatted;
9
10char* cmd_error(const char* msg, char* id)
11{
12 char* ret = malloc(strlen("? ") + strlen(msg) + (id ? strlen(id) : 0) + 3);
13 strcpy(ret, "?");
14 if(id)
15 {
16 strcat(ret, id);
17 free(id);
18 }
19 strcat(ret, " ");
20 strcat(ret, msg);
21 strcat(ret, "\n\n");
22 return ret;
23}
24
25char* cmd_success(const char* msg, char* id)
26{
27 char* ret = malloc(strlen("= ") + strlen(msg) + (id ? strlen(id) : 0) + 3);
28 strcpy(ret, "=");
29 if(id)
30 {
31 strcat(ret, id);
32 free(id);
33 }
34 strcat(ret, " ");
35 strcat(ret, msg);
36 strcat(ret, "\n\n");
37 return ret;
38}
39
40const char* const known_commands_string = "protocol_version\nname\nversion\nknown_command\nlist_commands\nquit\nboardsize\nclear_board\nkomi\nplay\ngenmove\nshowboard";
41const char* known_commands_array[] = {"protocol_version","name","version","known_command","list_commands","quit","boardsize","clear_board","komi","play","genmove","showboard"};
42int cmd_count = sizeof(known_commands_array)/sizeof(known_commands_array[0]);
43
44static msg_formatted format_msg(const char* msg)
45{
46 msg_formatted formatted = {0};
47
48 size_t index = 0;
49
50 while(isdigit(msg[index]) || msg[index] == '-')
51 index++;
52
53 if(index)
54 {
55 formatted.id = malloc(index+1);
56 strncpy(formatted.id, msg, index);
57 formatted.id[index] = '\0';
58 }
59
60 formatted.command = malloc(strlen(msg+index) + 1);
61 sscanf(msg+index, "%s", formatted.command);
62
63 formatted.arguments = new_vector();
64
65 char* tmp_msg = malloc(strlen(msg+index)+1);
66 strcpy(tmp_msg, msg+index);
67
68
69 char* current = strtok(tmp_msg, " ");
70 char* tmp_arg;
71
72 while(current)
73 {
74 tmp_arg = malloc(strlen(current)+1);
75 strcpy(tmp_arg, current);
76 vector_push(formatted.arguments, tmp_arg);
77 current = strtok(NULL, " ");
78 }
79
80 if(formatted.arguments->length > 1)
81 vector_remove(formatted.arguments, 0, free);
82
83 free(tmp_msg);
84
85 return formatted;
86}
87
88char* handle_gtp_cmd(const char* msg, game_state* game)
89{
90 if(!msg || !strlen(msg))
91 {
92 char* ret = calloc(1,1);
93 return ret;
94 }
95
96 msg_formatted formatted = format_msg(msg);
97 char* command = formatted.command;
98 Vector* arguments = formatted.arguments;
99 char* id = formatted.id;
100
101 char* (*func_ptr)(const char*, char* id) = cmd_error;
102 const char* func_args = "unknown command";
103
104 if(strcmp(command, "protocol_version") == 0)
105 {
106 func_ptr = cmd_success;
107 func_args = "2";
108 } else if(strcmp(command, "name") == 0) {
109 func_ptr = cmd_success;
110 func_args = "simple-go";
111 } else if(strcmp(command, "version") == 0) {
112 func_ptr = cmd_success;
113 func_args = "0.1";
114 } else if(strcmp(command, "known_command") == 0) {
115 func_ptr = cmd_success;
116 func_args = "false";
117 for(int i = 0; i < cmd_count; i++)
118 {
119 if(arguments->length > 0 && strcmp(vector_at(arguments, 0), known_commands_array[i]) == 0)
120 {
121 func_args = "true";
122 break;
123 }
124 }
125 } else if(strcmp(command, "list_commands") == 0) {
126 func_ptr = cmd_success;
127 func_args = known_commands_string;
128 } else if(strcmp(command, "boardsize") == 0) {
129 unsigned int size;
130 if(arguments->length == 1 && sscanf(vector_at(arguments,0), "%u", &size) > 0 && 0 < size && size < 26)
131 {
132 func_ptr = cmd_success;
133 func_args = "";
134 delete_board(game->board);
135 game->board = create_board(size);
136 } else {
137 func_ptr = cmd_error;
138 func_args = "unacceptable size";
139 }
140 } else if(strcmp(command, "komi") == 0) {
141 float komi;
142 if(arguments->length == 1 && sscanf(vector_at(arguments,0), "%f", &komi))
143 {
144 func_ptr = cmd_success;
145 func_args = "";
146 game->komi = komi;
147 } else {
148 func_ptr = cmd_error;
149 func_args = "komi not a float";
150 }
151 } else if(strcmp(command, "clear_board") == 0) {
152 func_ptr = cmd_success;
153 func_args = "";
154 unsigned int size = game->board->size;
155 delete_board(game->board);
156 game->board = create_board(size);
157 } else if(strcmp(command, "play") == 0) {
158 char* color = malloc(6);
159 char x;
160 int y;
161 if((arguments->length == 2 || arguments->length == 3) && //either its "a 10" or "a10"
162 (snprintf(color, 6, "%s", (char*)vector_at(arguments,0)) > 0) && //"white" and "black" are only 6 chars
163 (strcmp(color, "white") == 0 || strcmp(color, "black") == 0) && // check color
164 (sscanf(vector_at(arguments,1), "%c", &x) > 0) && // get horizontal coordinate
165 ((unsigned char)(tolower(x) - 'a') < game->board->size) && // check range
166 ((sscanf((char*)vector_at(arguments,1)+1, "%d", &y) > 0) || // get vertical coordinate if no space between
167 ((arguments->length == 3) && (sscanf((char*)vector_at(arguments,2), "%d", &y) > 0))) && // get vertical coordinate if space between
168 ((unsigned int)y <= game->board->size) && y > 0) // check range
169 {
170 if(play_at(game, game->board->size-(unsigned int)y, (unsigned char)(x-'a'), strcmp(color, "white") == 0 ? WHITE : BLACK))
171 {
172 func_ptr = cmd_success;
173 func_args = "";
174 } else {
175 func_ptr = cmd_error;
176 func_args = "illegal move";
177 }
178 } else {
179 func_ptr = cmd_error;
180 func_args = "invalid color or coordinate";
181 }
182 free(color);
183 } else if(strcmp(command, "genmove") == 0) {
184 func_ptr = cmd_success;
185 func_args = "";
186 go_coordinate y;
187 go_coordinate x;
188 do
189 {
190 y = (go_coordinate)rand() % game->board->size;
191 x = (go_coordinate)rand() % game->board->size;
192 } while(!play_at(game, y, x, NO_FIELD));
193 } else if(strcmp(command, "showboard") == 0) {
194 char* board = board_to_string(game->board);
195
196 free(command);
197 delete_vector(arguments, free);
198 char* tmp = cmd_success(board, id);
199 free(board);
200 return tmp;
201 }
202
203 free(command);
204 delete_vector(arguments, free);
205
206 return func_ptr(func_args, id);
207}
208