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