simple-go.c
Raw
1#include "simple-go.h"
2
3go_board* create_board(size_t size)
4{
5 go_board* board = malloc(sizeof(*board));
6 board->field_array = malloc(size*size*sizeof(*board->field_array));
7 for(size_t i = 0; i < size*size; i++)
8 {
9 board->field_array[i] = EMPTY;
10 }
11 board->size = size;
12
13 return board;
14}
15
16bool 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
24void delete_board(go_board* board)
25{
26 free(board->field_array);
27 free(board);
28}
29
30void print_board(go_board* board)
31{
32 for(size_t y = 0; y < board->size; y++)
33 {
34 for(size_t x = 0; x < board->size; x++)
35 {
36 putchar(get_board_at(board,y,x));
37 putchar(' ');
38 }
39 putchar('\n');
40 }
41}
42
43bool 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
117char get_board_at(go_board* board, size_t y, size_t x)
118{
119 if(check_bounds(board, y, x))
120 return board->field_array[y*board->size+x];
121 else
122 return INVALID_FIELD;
123}
124
125void set_board_at(go_board* board, size_t y, size_t x, char item)
126{
127 if(check_bounds(board,y,x))
128 board->field_array[y*board->size+x] = item;
129}
130
131void find_group(go_board* board, go_board* overlay, size_t y, size_t x)
132{
133 assert(board->size == overlay->size);
134 assert(check_bounds(board, y, x));
135
136 set_board_at(overlay, y, x, GROUP);
137 char field = get_board_at(board,y,x);
138
139 if(get_board_at(board,y-1,x) == field && get_board_at(overlay,y-1,x) == EMPTY)
140 find_group(board, overlay, y-1, x);
141
142 if(get_board_at(board,y,x-1) == field && get_board_at(overlay,y,x-1) == EMPTY)
143 find_group(board, overlay, y, x-1);
144
145 if(get_board_at(board,y+1,x) == field && get_board_at(overlay,y+1,x) == EMPTY)
146 find_group(board, overlay, y+1, x);
147
148 if(get_board_at(board,y,x+1) == field && get_board_at(overlay,y,x+1) == EMPTY)
149 find_group(board, overlay, y, x+1);
150}
151
152size_t count_liberties(go_board* board, go_board* overlay)
153{
154 assert(board->size == overlay->size);
155
156 go_board* tmpoverlay = create_board(board->size);
157 memcpy(tmpoverlay->field_array, overlay->field_array, board->size*board->size);
158
159 size_t liberties = 0;
160
161 for(size_t y = 0; y < board->size; y++)
162 {
163 for(size_t x = 0; x < board->size; x++)
164 {
165 if(get_board_at(overlay, y, x) == GROUP)
166 {
167 if(get_board_at(board,y-1,x) == EMPTY && get_board_at(tmpoverlay,y-1,x) != COUNTED)
168 {
169 liberties++;
170 set_board_at(tmpoverlay,y-1,x,COUNTED);
171 }
172 if(get_board_at(board,y,x-1) == EMPTY && get_board_at(tmpoverlay,y,x-1) != COUNTED)
173 {
174 liberties++;
175 set_board_at(tmpoverlay,y,x-1,COUNTED);
176 }
177 if(get_board_at(board,y+1,x) == EMPTY && get_board_at(tmpoverlay,y+1,x) != COUNTED)
178 {
179 liberties++;
180 set_board_at(tmpoverlay,y+1,x,COUNTED);
181 }
182 if(get_board_at(board,y,x+1) == EMPTY && get_board_at(tmpoverlay,y,x+1) != COUNTED)
183 {
184 liberties++;
185 set_board_at(tmpoverlay,y,x+1,COUNTED);
186 }
187
188 }
189 }
190 }
191
192 delete_board(tmpoverlay);
193
194 return liberties;
195}
196
197
198