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 //check if placement could lead to suicide
83 if(get_board_at(game->board, y-1, x) != EMPTY &&
84 get_board_at(game->board, y, x-1) != EMPTY &&
85 get_board_at(game->board, y+1, x) != EMPTY &&
86 get_board_at(game->board, y, x+1) != EMPTY)
87 //if so, check if placement kills a surrounding group
88 {
89 if(get_board_at(game->board, y-1, x) == (game->black_turn ? WHITE : BLACK))
90 {
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 delete_board(enemy_group);
97 return false;
98 } else {
99 kill_group(game->board, enemy_group);
100 }
101 }
102 if(get_board_at(game->board, y, x-1) == (game->black_turn ? WHITE : BLACK))
103 {
104 go_board* enemy_group = create_board(game->board->size);
105 find_group(game->board, enemy_group, y, x-1);
106 if(count_liberties(game->board, enemy_group) > 1)
107 {
108 delete_board(enemy_group);
109 return false;
110 } else {
111 kill_group(game->board, enemy_group);
112 }
113 }
114 if(get_board_at(game->board, y+1, x) == (game->black_turn ? WHITE : BLACK))
115 {
116 go_board* enemy_group = create_board(game->board->size);
117 find_group(game->board, enemy_group, y+1, x);
118 if(count_liberties(game->board, enemy_group) > 1)
119 {
120 delete_board(enemy_group);
121 return false;
122 } else {
123 kill_group(game->board, enemy_group);
124 }
125 }
126 if(get_board_at(game->board, y, x+1) == (game->black_turn ? WHITE : BLACK))
127 {
128 go_board* enemy_group = create_board(game->board->size);
129 find_group(game->board, enemy_group, y, x+1);
130 if(count_liberties(game->board, enemy_group) > 1)
131 {
132 delete_board(enemy_group);
133 return false;
134 } else {
135 kill_group(game->board, enemy_group);
136 }
137 }
138 //TODO: ...or if it connects to own group that has liberties left
139 }
140
141 set_board_at(game->board, y, x, game->black_turn ? BLACK : WHITE);
142 game->black_turn = !game->black_turn;
143 return true;
144}
145
146char get_board_at(go_board* board, size_t y, size_t x)
147{
148 if(check_bounds(board, y, x))
149 return board->field_array[y*board->size+x];
150 else
151 return INVALID_FIELD;
152}
153
154void set_board_at(go_board* board, size_t y, size_t x, char item)
155{
156 if(check_bounds(board,y,x))
157 board->field_array[y*board->size+x] = item;
158}
159
160void find_group(go_board* board, go_board* overlay, size_t y, size_t x)
161{
162 assert(board->size == overlay->size);
163 assert(check_bounds(board, y, x));
164
165 set_board_at(overlay, y, x, GROUP);
166 char field = get_board_at(board,y,x);
167
168 if(get_board_at(board,y-1,x) == field && get_board_at(overlay,y-1,x) == EMPTY)
169 find_group(board, overlay, y-1, x);
170
171 if(get_board_at(board,y,x-1) == field && get_board_at(overlay,y,x-1) == EMPTY)
172 find_group(board, overlay, y, x-1);
173
174 if(get_board_at(board,y+1,x) == field && get_board_at(overlay,y+1,x) == EMPTY)
175 find_group(board, overlay, y+1, x);
176
177 if(get_board_at(board,y,x+1) == field && get_board_at(overlay,y,x+1) == EMPTY)
178 find_group(board, overlay, y, x+1);
179}
180
181size_t count_liberties(go_board* board, go_board* overlay)
182{
183 assert(board->size == overlay->size);
184
185 go_board* tmpoverlay = create_board(board->size);
186 memcpy(tmpoverlay->field_array, overlay->field_array, board->size*board->size);
187
188 size_t liberties = 0;
189
190 for(size_t y = 0; y < board->size; y++)
191 {
192 for(size_t x = 0; x < board->size; x++)
193 {
194 if(get_board_at(overlay, y, x) == GROUP)
195 {
196 if(get_board_at(board,y-1,x) == EMPTY && get_board_at(tmpoverlay,y-1,x) != COUNTED)
197 {
198 liberties++;
199 set_board_at(tmpoverlay,y-1,x,COUNTED);
200 }
201 if(get_board_at(board,y,x-1) == EMPTY && get_board_at(tmpoverlay,y,x-1) != COUNTED)
202 {
203 liberties++;
204 set_board_at(tmpoverlay,y,x-1,COUNTED);
205 }
206 if(get_board_at(board,y+1,x) == EMPTY && get_board_at(tmpoverlay,y+1,x) != COUNTED)
207 {
208 liberties++;
209 set_board_at(tmpoverlay,y+1,x,COUNTED);
210 }
211 if(get_board_at(board,y,x+1) == EMPTY && get_board_at(tmpoverlay,y,x+1) != COUNTED)
212 {
213 liberties++;
214 set_board_at(tmpoverlay,y,x+1,COUNTED);
215 }
216
217 }
218 }
219 }
220
221 delete_board(tmpoverlay);
222
223 return liberties;
224}
225
226
227