added check_bound(), changed tests, added protoype for play_at()
MMakefile
| @@ -1,3 +1,4 @@ | |||
|---|---|---|---|
| 1 | 1 | all: | |
| 2 | 2 | gcc -O0 -g test.c simple-go.c -o test \ | |
| 3 | - | -Wall -Wpedantic -Wnull-dereference -Wshadow -Wconversion -Wstrict-prototypes -Wmissing-prototypes -Wcast-qual -Wstrict-overflow=5 -Wunreachable-code -Wno-unused-parameter | |
| 3 | + | -Wall -Wpedantic -Wnull-dereference -Wshadow -Wconversion -Wstrict-prototypes -Wmissing-prototypes -Wcast-qual -Wstrict-overflow=5 -Wunreachable-code -Wno-unused-parameter \ | |
| 4 | + | -fsanitize=undefined | |
Msimple-go.c
| @@ -13,6 +13,14 @@ go_board* create_board(size_t size) | |||
|---|---|---|---|
| 13 | 13 | return board; | |
| 14 | 14 | } | |
| 15 | 15 | ||
| 16 | + | bool check_bounds(go_board* board, size_t y, size_t x) | |
| 17 | + | { | |
| 18 | + | if(y >= 0 && x >= 0 && y < board->size && x < board->size) | |
| 19 | + | return true; | |
| 20 | + | else | |
| 21 | + | return false; | |
| 22 | + | } | |
| 23 | + | ||
| 16 | 24 | void delete_board(go_board* board) | |
| 17 | 25 | { | |
| 18 | 26 | free(board->field_array); | |
| @@ -32,9 +40,83 @@ void print_board(go_board* board) | |||
|---|---|---|---|
| 32 | 40 | } | |
| 33 | 41 | } | |
| 34 | 42 | ||
| 43 | + | bool play_at(game_state* game, size_t y, size_t x) | |
| 44 | + | { | |
| 45 | + | //check out-of-bounds | |
| 46 | + | if(!check_bounds(game->board, y, x)) | |
| 47 | + | return false; | |
| 48 | + | ||
| 49 | + | //check if field is empty | |
| 50 | + | if(get_board_at(game->board, y, x) != EMPTY) | |
| 51 | + | return false; | |
| 52 | + | ||
| 53 | + | //check if placement could lead to suicide | |
| 54 | + | if(get_board_at(game->board, y-1, x) != EMPTY && | |
| 55 | + | get_board_at(game->board, y, x-1) != EMPTY && | |
| 56 | + | get_board_at(game->board, y+1, x) != EMPTY && | |
| 57 | + | get_board_at(game->board, y, x+1) != EMPTY) | |
| 58 | + | //if so, check if placement kills a surrounding group | |
| 59 | + | { | |
| 60 | + | if(get_board_at(game->board, y-1, x) == (game->black_turn ? WHITE : BLACK)) | |
| 61 | + | { | |
| 62 | + | ||
| 63 | + | go_board* enemy_group = create_board(game->board->size); | |
| 64 | + | find_group(game->board, enemy_group, y-1, x); | |
| 65 | + | if(count_liberties(game->board, enemy_group) > 1) | |
| 66 | + | { | |
| 67 | + | delete_board(enemy_group); | |
| 68 | + | return false; | |
| 69 | + | } else { | |
| 70 | + | //TODO: kill_group(); | |
| 71 | + | } | |
| 72 | + | } | |
| 73 | + | if(get_board_at(game->board, y, x-1) == (game->black_turn ? WHITE : BLACK)) | |
| 74 | + | { | |
| 75 | + | go_board* enemy_group = create_board(game->board->size); | |
| 76 | + | find_group(game->board, enemy_group, y, x-1); | |
| 77 | + | if(count_liberties(game->board, enemy_group) > 1) | |
| 78 | + | { | |
| 79 | + | delete_board(enemy_group); | |
| 80 | + | return false; | |
| 81 | + | } else { | |
| 82 | + | //kill_group(); | |
| 83 | + | } | |
| 84 | + | } | |
| 85 | + | if(get_board_at(game->board, y+1, x) == (game->black_turn ? WHITE : BLACK)) | |
| 86 | + | { | |
| 87 | + | go_board* enemy_group = create_board(game->board->size); | |
| 88 | + | find_group(game->board, enemy_group, y+1, x); | |
| 89 | + | if(count_liberties(game->board, enemy_group) > 1) | |
| 90 | + | { | |
| 91 | + | delete_board(enemy_group); | |
| 92 | + | return false; | |
| 93 | + | } else { | |
| 94 | + | //kill_group(); | |
| 95 | + | } | |
| 96 | + | } | |
| 97 | + | if(get_board_at(game->board, y, x+1) == (game->black_turn ? WHITE : BLACK)) | |
| 98 | + | { | |
| 99 | + | go_board* enemy_group = create_board(game->board->size); | |
| 100 | + | find_group(game->board, enemy_group, y, x+1); | |
| 101 | + | if(count_liberties(game->board, enemy_group) > 1) | |
| 102 | + | { | |
| 103 | + | delete_board(enemy_group); | |
| 104 | + | return false; | |
| 105 | + | } else { | |
| 106 | + | //kill_group(); | |
| 107 | + | } | |
| 108 | + | } | |
| 109 | + | //TODO: ...or if it connects to own group that has liberties left | |
| 110 | + | } | |
| 111 | + | ||
| 112 | + | set_board_at(game->board, y, x, game->black_turn ? BLACK : WHITE); | |
| 113 | + | game->black_turn = !game->black_turn; | |
| 114 | + | return true; | |
| 115 | + | } | |
| 116 | + | ||
| 35 | 117 | char get_board_at(go_board* board, size_t y, size_t x) | |
| 36 | 118 | { | |
| 37 | - | if(y >= 0 && x >= 0 && y < board->size && x < board->size) | |
| 119 | + | if(check_bounds(board, y, x)) | |
| 38 | 120 | return board->field_array[y*board->size+x]; | |
| 39 | 121 | else | |
| 40 | 122 | return INVALID_FIELD; | |
| @@ -42,13 +124,14 @@ char get_board_at(go_board* board, size_t y, size_t x) | |||
|---|---|---|---|
| 42 | 124 | ||
| 43 | 125 | void set_board_at(go_board* board, size_t y, size_t x, char item) | |
| 44 | 126 | { | |
| 45 | - | if(y >= 0 && x >= 0 && y < board->size && x < board->size) | |
| 127 | + | if(check_bounds(board,y,x)) | |
| 46 | 128 | board->field_array[y*board->size+x] = item; | |
| 47 | 129 | } | |
| 48 | - | #include <unistd.h> | |
| 130 | + | ||
| 49 | 131 | void find_group(go_board* board, go_board* overlay, size_t y, size_t x) | |
| 50 | 132 | { | |
| 51 | 133 | assert(board->size == overlay->size); | |
| 134 | + | assert(check_bounds(board, y, x)); | |
| 52 | 135 | ||
| 53 | 136 | set_board_at(overlay, y, x, GROUP); | |
| 54 | 137 | char field = get_board_at(board,y,x); | |
| @@ -106,6 +189,8 @@ size_t count_liberties(go_board* board, go_board* overlay) | |||
|---|---|---|---|
| 106 | 189 | } | |
| 107 | 190 | } | |
| 108 | 191 | ||
| 192 | + | delete_board(tmpoverlay); | |
| 193 | + | ||
| 109 | 194 | return liberties; | |
| 110 | 195 | } | |
| 111 | 196 | ||
Msimple-go.h
| @@ -22,12 +22,14 @@ typedef struct go_board | |||
|---|---|---|---|
| 22 | 22 | ||
| 23 | 23 | typedef struct game_state | |
| 24 | 24 | { | |
| 25 | - | struct go_board* board; | |
| 25 | + | go_board* board; | |
| 26 | 26 | bool black_turn; | |
| 27 | 27 | } game_state; | |
| 28 | 28 | ||
| 29 | 29 | ||
| 30 | 30 | go_board* create_board(size_t size); | |
| 31 | + | bool play_at(game_state* game, size_t y, size_t x); | |
| 32 | + | bool check_bounds(go_board* board, size_t y, size_t x); | |
| 31 | 33 | void delete_board(go_board* board); | |
| 32 | 34 | char get_board_at(go_board* board, size_t y, size_t x); | |
| 33 | 35 | void set_board_at(go_board* board, size_t y, size_t x, char item); | |
Mtest.c
| @@ -4,19 +4,24 @@ int main(int argc, char** argv) | |||
|---|---|---|---|
| 4 | 4 | { | |
| 5 | 5 | go_board* test_board = create_board(5); | |
| 6 | 6 | ||
| 7 | - | set_board_at(test_board,2,2,WHITE); | |
| 8 | - | set_board_at(test_board,2,3,WHITE); | |
| 9 | - | set_board_at(test_board,1,3,WHITE); | |
| 10 | - | set_board_at(test_board,3,3,WHITE); | |
| 7 | + | set_board_at(test_board, 2, 2, WHITE); | |
| 8 | + | set_board_at(test_board, 2, 3, WHITE); | |
| 9 | + | set_board_at(test_board, 1, 3, WHITE); | |
| 10 | + | set_board_at(test_board, 3, 3, WHITE); | |
| 11 | + | set_board_at(test_board, 4, 4, WHITE); | |
| 12 | + | set_board_at(test_board, 3, 1, WHITE); | |
| 13 | + | set_board_at(test_board, 3, 2, BLACK); | |
| 11 | 14 | ||
| 12 | 15 | print_board(test_board); | |
| 13 | 16 | putchar('\n'); | |
| 14 | 17 | ||
| 15 | 18 | go_board* overlay = create_board(5); | |
| 16 | - | find_group(test_board, overlay,2,2); | |
| 19 | + | find_group(test_board, overlay, 2, 2); | |
| 17 | 20 | ||
| 18 | 21 | print_board(overlay); | |
| 19 | 22 | ||
| 20 | 23 | printf("liberties: %ld\n", count_liberties(test_board,overlay)); | |
| 24 | + | delete_board(test_board); | |
| 25 | + | delete_board(overlay); | |
| 21 | 26 | ||
| 22 | 27 | } | |