Prototype for gtp protocol
M.gitignore
@@ -1,6 +1,13 @@
# Binaries
test
#cutils files
cutils.h
cutils_endian.h
dyn_string.h
libcutils.so
vector.h
# Prerequisites
*.d
@@ -52,4 +59,4 @@ test
modules.order
Module.symvers
Mkfile.old
dkms.conf
dkms.conf
MMakefile
@@ -1,4 +1,3 @@
all:
gcc -Og -g test.c simple-go.c -o test -std=c11 \
-Wall -Wextra -Wpedantic -Wnull-dereference -Wshadow -Wconversion -Wstrict-prototypes -Wmissing-prototypes -Wcast-qual -Wstrict-overflow=5 -Wunreachable-code -Wno-unused-parameter \
-fsanitize=undefined
gcc -L./ -lcutils -O0 -g test.c simple-go.c simple-gtp.c -o test -std=c11 \
-Wall -Wextra -Wpedantic -Wnull-dereference -Wshadow -Wconversion -Wstrict-prototypes -Wmissing-prototypes -Wcast-qual -Wstrict-overflow=5 -Wunreachable-code -Wno-unused-parameter -Wno-missing-prototypes \
Msimple-go.c
@@ -1,12 +1,12 @@
#include "simple-go.h"
go_board* create_board(size_t size)
go_board* create_board(unsigned int size)
{
go_board* board = malloc(sizeof(*board));
assert(board);
board->field_array = malloc(size*size*sizeof(*board->field_array));
assert(board->field_array);
for(size_t i = 0; i < size*size; i++)
for(unsigned int i = 0; i < size*size; i++)
{
board->field_array[i] = EMPTY;
}
@@ -21,11 +21,12 @@ void delete_board(go_board* board)
free(board);
}
game_state* create_game(size_t size)
game_state* create_game(unsigned int size, float komi)
{
game_state* game = malloc(sizeof(*game));
game->board = create_board(size);
game->black_turn = true;
game->komi = komi;
return game;
}
@@ -36,7 +37,7 @@ void delete_game(game_state* game)
free(game);
}
bool check_bounds(go_board* board, size_t y, size_t x)
bool check_bounds(go_board* board, unsigned int y, unsigned int x)
{
if(y < board->size && x < board->size)
return true;
@@ -46,9 +47,9 @@ bool check_bounds(go_board* board, size_t y, size_t x)
void kill_group(go_board* board, go_board* overlay)
{
for(size_t y = 0; y < board->size; y++)
for(unsigned int y = 0; y < board->size; y++)
{
for(size_t x = 0; x < board->size; x++)
for(unsigned int x = 0; x < board->size; x++)
{
if(get_board_at(overlay, y, x) == GROUP)
set_board_at(board, y, x, EMPTY);
@@ -58,9 +59,9 @@ void kill_group(go_board* board, go_board* overlay)
void print_board(go_board* board)
{
for(size_t y = 0; y < board->size; y++)
for(unsigned int y = 0; y < board->size; y++)
{
for(size_t x = 0; x < board->size; x++)
for(unsigned int x = 0; x < board->size; x++)
{
putchar(get_board_at(board,y,x));
putchar(' ');
@@ -69,7 +70,7 @@ void print_board(go_board* board)
}
}
bool play_at(game_state* game, size_t y, size_t x)
bool play_at(game_state* game, unsigned int y, unsigned int x)
{
//check out-of-bounds
if(!check_bounds(game->board, y, x))
@@ -116,6 +117,7 @@ bool play_at(game_state* game, size_t y, size_t x)
kill_group(game->board, enemy_group);
can_place = true;
}
delete_board(enemy_group);
} else if(left == EMPTY) {
can_place = true;
} else {
@@ -135,6 +137,7 @@ bool play_at(game_state* game, size_t y, size_t x)
kill_group(game->board, enemy_group);
can_place = true;
}
delete_board(enemy_group);
} else if(down == EMPTY) {
can_place = true;
} else {
@@ -154,6 +157,7 @@ bool play_at(game_state* game, size_t y, size_t x)
kill_group(game->board, enemy_group);
can_place = true;
}
delete_board(enemy_group);
} else if(right == EMPTY) {
can_place = true;
} else {
@@ -172,7 +176,7 @@ bool play_at(game_state* game, size_t y, size_t x)
return true;
}
char get_board_at(go_board* board, size_t y, size_t x)
char get_board_at(go_board* board, unsigned int y, unsigned int x)
{
if(check_bounds(board, y, x))
return board->field_array[y*board->size+x];
@@ -180,45 +184,46 @@ char get_board_at(go_board* board, size_t y, size_t x)
return INVALID_FIELD;
}
void set_board_at(go_board* board, size_t y, size_t x, char item)
void set_board_at(go_board* board, unsigned int y, unsigned int x, char item)
{
if(check_bounds(board,y,x))
board->field_array[y*board->size+x] = item;
}
void find_group(go_board* board, go_board* overlay, size_t y, size_t x)
void find_group(go_board* board, go_board* overlay, unsigned int y, unsigned int x)
{
assert(board->size == overlay->size);
assert(check_bounds(board, y, x));
set_board_at(overlay, y, x, GROUP);
char field = get_board_at(board,y,x);
if(check_bounds(board, y, x))
{
set_board_at(overlay, y, x, GROUP);
char field = get_board_at(board,y,x);
if(get_board_at(board,y-1,x) == field && get_board_at(overlay,y-1,x) == EMPTY)
find_group(board, overlay, y-1, x);
if(get_board_at(board,y-1,x) == field && get_board_at(overlay,y-1,x) == EMPTY)
find_group(board, overlay, y-1, x);
if(get_board_at(board,y,x-1) == field && get_board_at(overlay,y,x-1) == EMPTY)
find_group(board, overlay, y, x-1);
if(get_board_at(board,y,x-1) == field && get_board_at(overlay,y,x-1) == EMPTY)
find_group(board, overlay, y, x-1);
if(get_board_at(board,y+1,x) == field && get_board_at(overlay,y+1,x) == EMPTY)
find_group(board, overlay, y+1, x);
if(get_board_at(board,y+1,x) == field && get_board_at(overlay,y+1,x) == EMPTY)
find_group(board, overlay, y+1, x);
if(get_board_at(board,y,x+1) == field && get_board_at(overlay,y,x+1) == EMPTY)
find_group(board, overlay, y, x+1);
if(get_board_at(board,y,x+1) == field && get_board_at(overlay,y,x+1) == EMPTY)
find_group(board, overlay, y, x+1);
}
}
size_t count_liberties(go_board* board, go_board* overlay)
unsigned long count_liberties(go_board* board, go_board* overlay)
{
assert(board->size == overlay->size);
go_board* tmpoverlay = create_board(board->size);
memcpy(tmpoverlay->field_array, overlay->field_array, board->size*board->size);
size_t liberties = 0;
unsigned long liberties = 0;
for(size_t y = 0; y < board->size; y++)
for(unsigned int y = 0; y < board->size; y++)
{
for(size_t x = 0; x < board->size; x++)
for(unsigned int x = 0; x < board->size; x++)
{
if(get_board_at(overlay, y, x) == GROUP)
{
Msimple-go.h
@@ -17,31 +17,32 @@
typedef struct go_board
{
char* field_array;
size_t size;
unsigned int size;
} go_board;
typedef struct game_state
{
go_board* board;
float komi;
bool black_turn;
} game_state;
go_board* create_board(size_t size);
go_board* create_board(unsigned int size);
void delete_board(go_board* board);
game_state* create_game(size_t size);
game_state* create_game(unsigned int size, float komi);
void delete_game(game_state* game);
bool check_bounds(go_board* board, size_t y, size_t x);
char get_board_at(go_board* board, size_t y, size_t x);
void set_board_at(go_board* board, size_t y, size_t x, char item);
bool check_bounds(go_board* board, unsigned int y, unsigned int x);
char get_board_at(go_board* board, unsigned int y, unsigned int x);
void set_board_at(go_board* board, unsigned int y, unsigned int x, char item);
void kill_group(go_board* board, go_board* overlay);
bool play_at(game_state* game, size_t y, size_t x);
bool play_at(game_state* game, unsigned int y, unsigned int x);
void print_board(go_board* board);
void find_group(go_board* board, go_board* overlay, size_t y, size_t x);
size_t count_liberties(go_board* board, go_board* overlay);
void find_group(go_board* board, go_board* overlay, unsigned int y, unsigned int x);
unsigned long count_liberties(go_board* board, go_board* overlay);
Asimple-gtp.c
@@ -0,0 +1,147 @@
#include "simple-gtp.h"
char* cmd_error(const char* msg)
{
char* ret = malloc(strlen("? ") + strlen(msg) + 1);
strcpy(ret, "? ");
strcat(ret, msg);
return ret;
}
char* cmd_success(const char* msg)
{
char* ret = malloc(strlen("= ") + strlen(msg) + 2);
strcpy(ret, "= ");
strcat(ret, msg);
return ret;
}
const char* const known_commands_string = "protocol_version\nname\nversion\nknown_command\nlist_commands\nquit\nboardsize\nclear_board\nkomi\nplay\ngenmove\nshowboard";
const char* known_commands_array[] = {"protocol_version","name","version","known_command","list_commands","quit","boardsize","clear_board","komi","play","genmove","showboard"};
int cmd_count = sizeof(known_commands_array)/sizeof(known_commands_array[0]);
char* handle_gtp_cmd(const char* msg, game_state* game)
{
if(!msg || !strlen(msg))
{
char* ret = calloc(1,1);
return ret;
}
char* command = malloc(strlen(msg) + 1);
sscanf(msg, "%s", command);
Vector* arguments = new_vector();
char* tmp_msg = malloc(strlen(msg)+1);
strcpy(tmp_msg, msg);
char* current = strtok(tmp_msg, " ");
char* tmp_arg;
while(current)
{
tmp_arg = malloc(strlen(current)+1);
strcpy(tmp_arg, current);
vector_push(arguments, tmp_arg);
current = strtok(NULL, " ");
}
char* (*func_ptr)(const char*) = cmd_error;
const char* func_args = "unknown command";
if(strcmp(command, "protocol_version") == 0)
{
func_ptr = cmd_success;
func_args = "2";
} else if(strcmp(command, "name") == 0) {
func_ptr = cmd_success;
func_args = "simple-go";
} else if(strcmp(command, "version") == 0) {
func_ptr = cmd_success;
func_args = "0.1";
} else if(strcmp(command, "known_command") == 0) {
func_ptr = cmd_success;
func_args = "false";
for(int i = 0; i < cmd_count; i++)
{
if(arguments->length > 0 && strcmp(vector_at(arguments, 0), known_commands_array[i]) == 0)
{
func_args = "true";
break;
}
}
} else if(strcmp(command, "list_commands") == 0) {
func_ptr = cmd_success;
func_args = known_commands_string;
} else if(strcmp(command, "boardsize") == 0) {
unsigned int size;
if(arguments->length == 1 && sscanf(vector_at(arguments,0), "%u", &size) > 0 && 0 < size && size < 26)
{
func_ptr = cmd_success;
func_args = "";
delete_board(game->board);
game->board = create_board(size);
} else {
func_ptr = cmd_error;
func_args = "unacceptable size";
}
} else if(strcmp(command, "komi") == 0) {
float komi;
if(arguments->length == 1 && sscanf(vector_at(arguments,0), "%f", &komi))
{
func_ptr = cmd_success;
func_args = "";
game->komi = komi;
} else {
func_ptr = cmd_error;
func_args = "komi not a float";
}
} else if(strcmp(command, "clear_board") == 0) {
unsigned int size = game->board->size;
delete_board(game->board);
game->board = create_board(size);
} else if(strcmp(command, "play") == 0) {
char* color = malloc(6);
char y;
int x;
if((arguments->length == 2 || arguments->length == 3) &&
(snprintf(color, 6, "%s", (char*)vector_at(arguments,0)) > 0) &&
(strcmp(color, "white") == 0 || strcmp(color, "black") == 0) &&
(sscanf(vector_at(arguments,1), "%c", &y) > 0) &&
((unsigned char)(tolower(y) - 'a') < game->board->size) &&
(sscanf((char*)vector_at(arguments,1)+1, "%d", &x) > 0) &&
((unsigned int)x <= game->board->size) && (unsigned int)x > 0)
{
if(play_at(game, (unsigned char)(y-'a'), (unsigned int)x-1))
{
func_ptr = cmd_success;
func_args = "";
} else {
func_ptr = cmd_error;
func_args = "illegal move";
}
} else {
func_ptr = cmd_error;
func_args = "invalid color or coordinate";
}
free(color);
} else if(strcmp(command, "genmove") == 0) {
unsigned int y;
unsigned int x;
do
{
y = (unsigned int)rand() % game->board->size;
x = (unsigned int)rand() % game->board->size;
} while(!play_at(game, y, x));
}
free(command);
delete_vector(arguments, NULL);
free(arguments);
free(tmp_msg);
return func_ptr(func_args);
}
Asimple-gtp.h
@@ -0,0 +1,13 @@
#ifndef SIMPLE_GTP_H
#define SIMPLE_GTP_H
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "simple-go.h"
#include "cutils.h"
char* handle_gtp_cmd(const char* msg, game_state* game);
#endif //SIMPLE_GTP_H
Mtest.c
@@ -1,4 +1,5 @@
#include "simple-go.h"
#include "simple-gtp.h"
void test1(void)
{
@@ -35,12 +36,13 @@ void test1(void)
void test2(void)
{
puts("test2 running");
game_state* test_game = create_game(5);
game_state* test_game = create_game(5, 0);
go_board* test_board = test_game->board;
set_board_at(test_board, 2, 3, WHITE);
set_board_at(test_board, 3, 2, WHITE);
set_board_at(test_board, 1, 2, WHITE);
set_board_at(test_board, 2, 1, WHITE);
set_board_at(test_board, 1, 1, BLACK);
play_at(test_game, 2, 2);
print_board(test_game->board);
@@ -58,10 +60,27 @@ void test2(void)
puts("test2 finished");
}
void test3(void)
{
puts("test2 running");
game_state* test_game = create_game(11, 0);
char* ret =handle_gtp_cmd("play white a9", test_game);
printf("%s\n", ret);
print_board(test_game->board);
free(ret);
delete_game(test_game);
puts("test2 finished");
}
int main(int argc, char** argv)
{
test1();
test2();
test3();
}