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 assert(board);
7 board->field_array = malloc(size*size*sizeof(*board->field_array));
8 assert(board->field_array);
9 for(size_t i = 0; i < size*size; i++)
10 {
11 board->field_array[i] = EMPTY;
12 }
13 board->size = size;
14
15 return board;
16}
17
18void delete_board(go_board* board)
19{
20 free(board->field_array);
21 free(board);
22}
23
24game_state* create_game(size_t size)
25{
26 game_state* game = malloc(sizeof(*game));
27 game->board = create_board(size);
28 game->black_turn = true;
29
30 return game;
31}
32
33void delete_game(game_state* game)
34{
35 delete_board(game->board);
36 free(game);
37}
38
39bool check_bounds(go_board* board, size_t y, size_t x)
40{
41 if(y < board->size && x < board->size)
42 return true;
43 else
44 return false;
45}
46
47void kill_group(go_board* board, go_board* overlay)
48{
49 for(size_t y = 0; y < board->size; y++)
50 {
51 for(size_t x = 0; x < board->size; x++)
52 {
53 if(get_board_at(overlay, y, x) == GROUP)
54 set_board_at(board, y, x, EMPTY);
55 }
56 }
57}
58
59void print_board(go_board* board)
60{
61 for(size_t y = 0; y < board->size; y++)
62 {
63 for(size_t x = 0; x < board->size; x++)
64 {
65 putchar(get_board_at(board,y,x));
66 putchar(' ');
67 }
68 putchar('\n');
69 }
70}
71
72bool play_at(game_state* game, size_t y, size_t x)
73{
74 //check out-of-bounds
75 if(!check_bounds(game->board, y, x))
76 return false;
77
78 //check if field is empty
79 if(get_board_at(game->board, y, x) != EMPTY)
80 return false;
81
82 bool can_place = false;
83
84 char up = get_board_at(game->board, y-1, x);
85 char left = get_board_at(game->board, y, x-1);
86 char down = get_board_at(game->board, y+1, x);
87 char right = get_board_at(game->board, y, x+1);
88
89 //first check for group to kill, then for empty field, and last for group woth liberties
90 if(up == (game->black_turn ? WHITE : BLACK))
91 {
92 go_board* enemy_group = create_board(game->board->size);
93 find_group(game->board, enemy_group, y-1, x);
94 if(count_liberties(game->board, enemy_group) <= 1)
95 {
96 kill_group(game->board, enemy_group);
97 can_place = true;
98 }
99 delete_board(enemy_group);
100 } else if(up == EMPTY) {
101 can_place = true;
102 } else {
103 go_board* friendly_group = create_board(game->board->size);
104 find_group(game->board, friendly_group, y-1, x);
105 if(count_liberties(game->board, friendly_group) > 1)
106 can_place = true;
107 delete_board(friendly_group);
108 }
109
110 if(left == (game->black_turn ? WHITE : BLACK))
111 {
112 go_board* enemy_group = create_board(game->board->size);
113 find_group(game->board, enemy_group, y, x-1);
114 if(count_liberties(game->board, enemy_group) <= 1)
115 {
116 kill_group(game->board, enemy_group);
117 can_place = true;
118 }
119 } else if(left == EMPTY) {
120 can_place = true;
121 } else {
122 go_board* friendly_group = create_board(game->board->size);
123 find_group(game->board, friendly_group, y, x-1);
124 if(count_liberties(game->board, friendly_group) > 1)
125 can_place = true;
126 delete_board(friendly_group);
127 }
128
129 if(down == (game->black_turn ? WHITE : BLACK))
130 {
131 go_board* enemy_group = create_board(game->board->size);
132 find_group(game->board, enemy_group, y+1, x);
133 if(count_liberties(game->board, enemy_group) <= 1)
134 {
135 kill_group(game->board, enemy_group);
136 can_place = true;
137 }
138 } else if(down == EMPTY) {
139 can_place = true;
140 } else {
141 go_board* friendly_group = create_board(game->board->size);
142 find_group(game->board, friendly_group, y+1, x);
143 if(count_liberties(game->board, friendly_group) > 1)
144 can_place = true;
145 delete_board(friendly_group);
146 }
147
148 if(right == (game->black_turn ? WHITE : BLACK))
149 {
150 go_board* enemy_group = create_board(game->board->size);
151 find_group(game->board, enemy_group, y, x+1);
152 if(count_liberties(game->board, enemy_group) <= 1)
153 {
154 kill_group(game->board, enemy_group);
155 can_place = true;
156 }
157 } else if(right == EMPTY) {
158 can_place = true;
159 } else {
160 go_board* friendly_group = create_board(game->board->size);
161 find_group(game->board, friendly_group, y, x+1);
162 if(count_liberties(game->board, friendly_group) > 1)
163 can_place = true;
164 delete_board(friendly_group);
165 }
166
167 if(!can_place)
168 return false;
169
170 set_board_at(game->board, y, x, game->black_turn ? BLACK : WHITE);
171 game->black_turn = !game->black_turn;
172 return true;
173}
174
175char get_board_at(go_board* board, size_t y, size_t x)
176{
177 if(check_bounds(board, y, x))
178 return board->field_array[y*board->size+x];
179 else
180 return INVALID_FIELD;
181}
182
183void set_board_at(go_board* board, size_t y, size_t x, char item)
184{
185 if(check_bounds(board,y,x))
186 board->field_array[y*board->size+x] = item;
187}
188
189void find_group(go_board* board, go_board* overlay, size_t y, size_t x)
190{
191 assert(board->size == overlay->size);
192 assert(check_bounds(board, y, x));
193
194 set_board_at(overlay, y, x, GROUP);
195 char field = get_board_at(board,y,x);
196
197 if(get_board_at(board,y-1,x) == field && get_board_at(overlay,y-1,x) == EMPTY)
198 find_group(board, overlay, y-1, x);
199
200 if(get_board_at(board,y,x-1) == field && get_board_at(overlay,y,x-1) == EMPTY)
201 find_group(board, overlay, y, x-1);
202
203 if(get_board_at(board,y+1,x) == field && get_board_at(overlay,y+1,x) == EMPTY)
204 find_group(board, overlay, y+1, x);
205
206 if(get_board_at(board,y,x+1) == field && get_board_at(overlay,y,x+1) == EMPTY)
207 find_group(board, overlay, y, x+1);
208}
209
210size_t count_liberties(go_board* board, go_board* overlay)
211{
212 assert(board->size == overlay->size);
213
214 go_board* tmpoverlay = create_board(board->size);
215 memcpy(tmpoverlay->field_array, overlay->field_array, board->size*board->size);
216
217 size_t liberties = 0;
218
219 for(size_t y = 0; y < board->size; y++)
220 {
221 for(size_t x = 0; x < board->size; x++)
222 {
223 if(get_board_at(overlay, y, x) == GROUP)
224 {
225 if(get_board_at(board,y-1,x) == EMPTY && get_board_at(tmpoverlay,y-1,x) != COUNTED)
226 {
227 liberties++;
228 set_board_at(tmpoverlay,y-1,x,COUNTED);
229 }
230 if(get_board_at(board,y,x-1) == EMPTY && get_board_at(tmpoverlay,y,x-1) != COUNTED)
231 {
232 liberties++;
233 set_board_at(tmpoverlay,y,x-1,COUNTED);
234 }
235 if(get_board_at(board,y+1,x) == EMPTY && get_board_at(tmpoverlay,y+1,x) != COUNTED)
236 {
237 liberties++;
238 set_board_at(tmpoverlay,y+1,x,COUNTED);
239 }
240 if(get_board_at(board,y,x+1) == EMPTY && get_board_at(tmpoverlay,y,x+1) != COUNTED)
241 {
242 liberties++;
243 set_board_at(tmpoverlay,y,x+1,COUNTED);
244 }
245
246 }
247 }
248 }
249
250 delete_board(tmpoverlay);
251
252 return liberties;
253}
254
255
256