refactored handle_gtp_cmd(), added id for gtp command, added tests
Msimple-go.c
| @@ -134,21 +134,21 @@ bool play_at(game_state* game, go_coordinate y, go_coordinate x) | |||
|---|---|---|---|
| 134 | 134 | can_place = true; | |
| 135 | 135 | else if(left == EMPTY) | |
| 136 | 136 | can_place = true; | |
| 137 | - | else if(up == friendly && group_attachable(game, y, x-1)) | |
| 137 | + | else if(left == friendly && group_attachable(game, y, x-1)) | |
| 138 | 138 | can_place = true; | |
| 139 | 139 | ||
| 140 | 140 | if(down == enemy && group_killable(game, y+1, x)) | |
| 141 | 141 | can_place = true; | |
| 142 | 142 | else if(down == EMPTY) | |
| 143 | 143 | can_place = true; | |
| 144 | - | else if(up == friendly && group_attachable(game, y+1, x)) | |
| 144 | + | else if(down == friendly && group_attachable(game, y+1, x)) | |
| 145 | 145 | can_place = true; | |
| 146 | 146 | ||
| 147 | 147 | if(right == enemy && group_killable(game, y, x+1)) | |
| 148 | 148 | can_place = true; | |
| 149 | 149 | else if(right == EMPTY) | |
| 150 | 150 | can_place = true; | |
| 151 | - | else if(up == friendly && group_attachable(game, y, x+1)) | |
| 151 | + | else if(right == friendly && group_attachable(game, y, x+1)) | |
| 152 | 152 | can_place = true; | |
| 153 | 153 | ||
| 154 | 154 | if(!can_place) | |
Msimple-go.h
| @@ -31,22 +31,22 @@ typedef struct game_state | |||
|---|---|---|---|
| 31 | 31 | } game_state; | |
| 32 | 32 | ||
| 33 | 33 | ||
| 34 | - | go_board* create_board(unsigned int size); | |
| 34 | + | go_board* create_board(go_coordinate size); | |
| 35 | 35 | void delete_board(go_board* board); | |
| 36 | - | game_state* create_game(unsigned int size, float komi); | |
| 36 | + | game_state* create_game(go_coordinate size, float komi); | |
| 37 | 37 | void delete_game(game_state* game); | |
| 38 | 38 | ||
| 39 | - | bool check_bounds(const go_board* board, unsigned int y, unsigned int x); | |
| 40 | - | char get_board_at(const go_board* board, unsigned int y, unsigned int x); | |
| 41 | - | void set_board_at(go_board* board, unsigned int y, unsigned int x, char item); | |
| 39 | + | bool check_bounds(const go_board* board, go_coordinate y, go_coordinate x); | |
| 40 | + | char get_board_at(const go_board* board, go_coordinate y, go_coordinate x); | |
| 41 | + | void set_board_at(go_board* board, go_coordinate y, go_coordinate x, char item); | |
| 42 | 42 | ||
| 43 | 43 | void kill_group(go_board* board, go_board* overlay); | |
| 44 | - | bool group_killable(game_state* game, unsigned int y, unsigned int x); | |
| 45 | - | bool group_attachable(const game_state* game, unsigned int y, unsigned int x); | |
| 46 | - | bool play_at(game_state* game, unsigned int y, unsigned int x); | |
| 44 | + | bool group_killable(game_state* game, go_coordinate y, go_coordinate x); | |
| 45 | + | bool group_attachable(const game_state* game, go_coordinate y, go_coordinate x); | |
| 46 | + | bool play_at(game_state* game, go_coordinate y, go_coordinate x); | |
| 47 | 47 | ||
| 48 | 48 | void print_board(go_board* board); | |
| 49 | - | void find_group(const go_board* board, go_board* overlay, unsigned int y, unsigned int x); | |
| 49 | + | void find_group(const go_board* board, go_board* overlay, go_coordinate y, go_coordinate x); | |
| 50 | 50 | unsigned long count_liberties(go_board* board, go_board* overlay); | |
| 51 | 51 | ||
| 52 | 52 | ||
Msimple-gtp.c
| @@ -1,18 +1,39 @@ | |||
|---|---|---|---|
| 1 | 1 | #include "simple-gtp.h" | |
| 2 | 2 | ||
| 3 | - | char* cmd_error(const char* msg) | |
| 3 | + | typedef struct msg_formatted | |
| 4 | 4 | { | |
| 5 | - | char* ret = malloc(strlen("? ") + strlen(msg) + 1); | |
| 6 | - | strcpy(ret, "? "); | |
| 5 | + | char* command; | |
| 6 | + | Vector* arguments; | |
| 7 | + | char* id; | |
| 8 | + | } msg_formatted; | |
| 9 | + | ||
| 10 | + | char* 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, " "); | |
| 7 | 20 | strcat(ret, msg); | |
| 21 | + | strcat(ret, "\n\n"); | |
| 8 | 22 | return ret; | |
| 9 | 23 | } | |
| 10 | 24 | ||
| 11 | - | char* cmd_success(const char* msg) | |
| 25 | + | char* cmd_success(const char* msg, char* id) | |
| 12 | 26 | { | |
| 13 | - | char* ret = malloc(strlen("= ") + strlen(msg) + 2); | |
| 14 | - | strcpy(ret, "= "); | |
| 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, " "); | |
| 15 | 35 | strcat(ret, msg); | |
| 36 | + | strcat(ret, "\n\n"); | |
| 16 | 37 | return ret; | |
| 17 | 38 | } | |
| 18 | 39 | ||
| @@ -20,21 +41,29 @@ const char* const known_commands_string = "protocol_version\nname\nversion\nknow | |||
|---|---|---|---|
| 20 | 41 | const char* known_commands_array[] = {"protocol_version","name","version","known_command","list_commands","quit","boardsize","clear_board","komi","play","genmove","showboard"}; | |
| 21 | 42 | int cmd_count = sizeof(known_commands_array)/sizeof(known_commands_array[0]); | |
| 22 | 43 | ||
| 23 | - | char* handle_gtp_cmd(const char* msg, game_state* game) | |
| 44 | + | static msg_formatted format_msg(const char* msg) | |
| 24 | 45 | { | |
| 25 | - | if(!msg || !strlen(msg)) | |
| 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) | |
| 26 | 54 | { | |
| 27 | - | char* ret = calloc(1,1); | |
| 28 | - | return ret; | |
| 55 | + | formatted.id = malloc(index+1); | |
| 56 | + | strncpy(formatted.id, msg, index); | |
| 57 | + | formatted.id[index] = '\0'; | |
| 29 | 58 | } | |
| 30 | 59 | ||
| 31 | - | char* command = malloc(strlen(msg) + 1); | |
| 32 | - | sscanf(msg, "%s", command); | |
| 60 | + | formatted.command = malloc(strlen(msg+index) + 1); | |
| 61 | + | sscanf(msg+index, "%s", formatted.command); | |
| 33 | 62 | ||
| 34 | - | Vector* arguments = new_vector(); | |
| 63 | + | formatted.arguments = new_vector(); | |
| 35 | 64 | ||
| 36 | - | char* tmp_msg = malloc(strlen(msg)+1); | |
| 37 | - | strcpy(tmp_msg, msg); | |
| 65 | + | char* tmp_msg = malloc(strlen(msg+index)+1); | |
| 66 | + | strcpy(tmp_msg, msg+index); | |
| 38 | 67 | ||
| 39 | 68 | ||
| 40 | 69 | char* current = strtok(tmp_msg, " "); | |
| @@ -44,14 +73,32 @@ char* handle_gtp_cmd(const char* msg, game_state* game) | |||
|---|---|---|---|
| 44 | 73 | { | |
| 45 | 74 | tmp_arg = malloc(strlen(current)+1); | |
| 46 | 75 | strcpy(tmp_arg, current); | |
| 47 | - | vector_push(arguments, tmp_arg); | |
| 76 | + | vector_push(formatted.arguments, tmp_arg); | |
| 48 | 77 | current = strtok(NULL, " "); | |
| 49 | 78 | } | |
| 50 | 79 | ||
| 51 | - | if(arguments->length > 1) | |
| 52 | - | vector_remove(arguments,0,free); | |
| 80 | + | if(formatted.arguments->length > 1) | |
| 81 | + | vector_remove(formatted.arguments, 0, free); | |
| 82 | + | ||
| 83 | + | free(tmp_msg); | |
| 53 | 84 | ||
| 54 | - | char* (*func_ptr)(const char*) = cmd_error; | |
| 85 | + | return formatted; | |
| 86 | + | } | |
| 87 | + | ||
| 88 | + | char* 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; | |
| 55 | 102 | const char* func_args = "unknown command"; | |
| 56 | 103 | ||
| 57 | 104 | if(strcmp(command, "protocol_version") == 0) | |
| @@ -102,6 +149,8 @@ char* handle_gtp_cmd(const char* msg, game_state* game) | |||
|---|---|---|---|
| 102 | 149 | func_args = "komi not a float"; | |
| 103 | 150 | } | |
| 104 | 151 | } else if(strcmp(command, "clear_board") == 0) { | |
| 152 | + | func_ptr = cmd_success; | |
| 153 | + | func_args = ""; | |
| 105 | 154 | unsigned int size = game->board->size; | |
| 106 | 155 | delete_board(game->board); | |
| 107 | 156 | game->board = create_board(size); | |
| @@ -109,13 +158,14 @@ char* handle_gtp_cmd(const char* msg, game_state* game) | |||
|---|---|---|---|
| 109 | 158 | char* color = malloc(6); | |
| 110 | 159 | char y; | |
| 111 | 160 | int x; | |
| 112 | - | if((arguments->length == 2 || arguments->length == 3) && | |
| 113 | - | (snprintf(color, 6, "%s", (char*)vector_at(arguments,0)) > 0) && | |
| 114 | - | (strcmp(color, "white") == 0 || strcmp(color, "black") == 0) && | |
| 115 | - | (sscanf(vector_at(arguments,1), "%c", &y) > 0) && | |
| 116 | - | ((unsigned char)(tolower(y) - 'a') < game->board->size) && | |
| 117 | - | (sscanf((char*)vector_at(arguments,1)+1, "%d", &x) > 0) && | |
| 118 | - | ((unsigned int)x <= game->board->size) && (unsigned int)x > 0) | |
| 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", &y) > 0) && //get vertical coordinate | |
| 165 | + | ((unsigned char)(tolower(y) - 'a') < game->board->size) && // check range | |
| 166 | + | ((sscanf((char*)vector_at(arguments,1)+1, "%d", &x) > 0) || // get horizontal coordinate if no space between | |
| 167 | + | ((arguments->length == 3) && (sscanf((char*)vector_at(arguments,2), "%d", &x) > 0))) && // get horizontal coordinate if space between | |
| 168 | + | ((unsigned int)x <= game->board->size) && ((unsigned int)x > 0)) // check range | |
| 119 | 169 | { | |
| 120 | 170 | if(play_at(game, (unsigned char)(y-'a'), (unsigned int)x-1)) | |
| 121 | 171 | { | |
| @@ -131,6 +181,8 @@ char* handle_gtp_cmd(const char* msg, game_state* game) | |||
|---|---|---|---|
| 131 | 181 | } | |
| 132 | 182 | free(color); | |
| 133 | 183 | } else if(strcmp(command, "genmove") == 0) { | |
| 184 | + | func_ptr = cmd_success; | |
| 185 | + | func_args = ""; | |
| 134 | 186 | unsigned int y; | |
| 135 | 187 | unsigned int x; | |
| 136 | 188 | do | |
| @@ -143,7 +195,6 @@ char* handle_gtp_cmd(const char* msg, game_state* game) | |||
|---|---|---|---|
| 143 | 195 | ||
| 144 | 196 | free(command); | |
| 145 | 197 | delete_vector(arguments, free); | |
| 146 | - | free(tmp_msg); | |
| 147 | 198 | ||
| 148 | - | return func_ptr(func_args); | |
| 199 | + | return func_ptr(func_args, id); | |
| 149 | 200 | } | |
Mtest.c
| @@ -62,19 +62,76 @@ void test2(void) | |||
|---|---|---|---|
| 62 | 62 | ||
| 63 | 63 | void test3(void) | |
| 64 | 64 | { | |
| 65 | - | puts("test2 running"); | |
| 65 | + | puts("test3 running"); | |
| 66 | 66 | ||
| 67 | 67 | game_state* test_game = create_game(11, 0); | |
| 68 | 68 | ||
| 69 | - | char* ret =handle_gtp_cmd("play white a9", test_game); | |
| 69 | + | char* ret =handle_gtp_cmd("play white a 10", test_game); | |
| 70 | 70 | printf("%s\n", ret); | |
| 71 | 71 | free(ret); | |
| 72 | 72 | print_board(test_game->board); | |
| 73 | 73 | ||
| 74 | + | ret =handle_gtp_cmd("version", test_game); | |
| 75 | + | printf("%s\n", ret); | |
| 76 | + | free(ret); | |
| 77 | + | ||
| 78 | + | ret =handle_gtp_cmd("komi -6.5", test_game); | |
| 79 | + | printf("%s\n", ret); | |
| 80 | + | printf("%f\n", test_game->komi); | |
| 81 | + | free(ret); | |
| 82 | + | ||
| 83 | + | ret =handle_gtp_cmd("protocol_version", test_game); | |
| 84 | + | printf("%s\n", ret); | |
| 85 | + | free(ret); | |
| 86 | + | ||
| 87 | + | ret =handle_gtp_cmd("known_command play", test_game); | |
| 88 | + | printf("%s\n", ret); | |
| 89 | + | free(ret); | |
| 90 | + | ||
| 91 | + | ret =handle_gtp_cmd("known_command what", test_game); | |
| 92 | + | printf("%s\n", ret); | |
| 93 | + | free(ret); | |
| 94 | + | ||
| 95 | + | ret =handle_gtp_cmd("list_commands", test_game); | |
| 96 | + | printf("%s\n", ret); | |
| 97 | + | free(ret); | |
| 98 | + | ||
| 99 | + | ret =handle_gtp_cmd("1clear_board", test_game); | |
| 100 | + | printf("%s\n", ret); | |
| 101 | + | free(ret); | |
| 102 | + | ||
| 103 | + | ret =handle_gtp_cmd("2boardsize 26", test_game); | |
| 104 | + | printf("%s\n", ret); | |
| 105 | + | free(ret); | |
| 106 | + | ||
| 107 | + | ret =handle_gtp_cmd("genmove", test_game); | |
| 108 | + | printf("%s\n", ret); | |
| 109 | + | free(ret); | |
| 110 | + | ||
| 111 | + | print_board(test_game->board); | |
| 112 | + | ||
| 74 | 113 | ||
| 75 | 114 | delete_game(test_game); | |
| 76 | 115 | ||
| 77 | - | puts("test2 finished"); | |
| 116 | + | puts("test3 finished"); | |
| 117 | + | } | |
| 118 | + | ||
| 119 | + | void test4(void) | |
| 120 | + | { | |
| 121 | + | puts("test4 running"); | |
| 122 | + | ||
| 123 | + | game_state* test_game = create_game(19, 6.5); | |
| 124 | + | go_board* test_board = test_game->board; | |
| 125 | + | set_board_at(test_board, 2, 3, WHITE); | |
| 126 | + | set_board_at(test_board, 2, 5, WHITE); | |
| 127 | + | set_board_at(test_board, 1, 4, WHITE); | |
| 128 | + | set_board_at(test_board, 3, 4, BLACK); | |
| 129 | + | play_at(test_game, 2,4); | |
| 130 | + | ||
| 131 | + | print_board(test_game->board); | |
| 132 | + | ||
| 133 | + | delete_game(test_game); | |
| 134 | + | puts("test4 finished"); | |
| 78 | 135 | } | |
| 79 | 136 | ||
| 80 | 137 | ||
| @@ -83,5 +140,6 @@ int main(int argc, char** argv) | |||
|---|---|---|---|
| 83 | 140 | test1(); | |
| 84 | 141 | test2(); | |
| 85 | 142 | test3(); | |
| 143 | + | test4(); | |
| 86 | 144 | ||
| 87 | 145 | } | |