board.c (8520B)
1 #include <ctype.h> 2 #include <stddef.h> 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <string.h> 6 7 #include <cii/assert.h> 8 #include <cii/except.h> 9 #include <cii/mem.h> 10 11 #include "board.h" 12 13 #define T Board_T 14 #define G Grave_T 15 16 #define MAX_MOVE 10 17 #define MAX_PLAY 1024 18 19 const Except_T BOARDE_MOVE = {"Board: Invalid move"}; 20 21 const char def_board[8][8] = {"rnbqkbnr", "pppppppp", " ", " ", 22 " ", " ", "PPPPPPPP", "RNBQKBNR"}; 23 static char piece_lookup[] = {'K', 'Q', 'R', 'B', 'N', 'P', 24 'k', 'q', 'r', 'b', 'n', 'p'}; 25 static int piece_value[] = {100, 8, 5, 3, 3, 1, 100, 8, 5, 3, 3, 1}; 26 struct G { 27 char arr[20]; 28 int size; 29 int value; 30 }; 31 32 struct T { 33 int turn; 34 char *board; 35 G white; 36 G black; 37 }; 38 39 typedef struct { 40 int x[8]; 41 int y[8]; 42 int size; 43 int limited; 44 } move_offset_t; 45 46 move_offset_t piece_offset[] = { 47 { {0, 0, 1, -1, -1, -1, 1, 1}, {-1, 1, 0, 0, -1, 1, 1, -1}, 8, 1}, 48 { {0, 0, 1, -1, -1, -1, 1, 1}, {-1, 1, 0, 0, -1, 1, 1, -1}, 8, 0}, 49 { {0, 0, 1, -1, 0, 0, 0, 0}, {-1, 1, 0, 0, 0, 0, 0, 0}, 4, 0}, 50 { {-1, -1, 1, 1, 0, 0, 0, 0}, {-1, 1, 1, -1, 0, 0, 0, 0}, 4, 0}, 51 {{-2, -1, 1, 2, 2, 1, -1, -2}, {1, 2, 2, 1, -1, -2, -2, -1}, 8, 1} 52 }; 53 54 void __grave_copy(G self, G new) { 55 new->size = self->size; 56 new->value = self->value; 57 for (int i = 0; i < self->size; i++) 58 new->arr[i] = self->arr[i]; 59 } 60 61 void __board_send_grave(T self, char piece, char color) { 62 G g = (color == 'w') ? self->white : self->black; 63 64 g->arr[g->size++] = piece; 65 g->value += piece_value[piece_get_index(piece)]; 66 } 67 68 char __board_get_at(T self, char file, int rank) { 69 if (file > 'h' || file < 'a' || rank < 1 || rank > 8) 70 return '!'; 71 return self->board[(8 - rank) * 8 + file - 'a']; 72 } 73 74 void __board_set_at(T self, char file, int rank, char to) { 75 self->board[(8 - rank) * 8 + file - 'a'] = to; 76 } 77 78 typedef int (*__board_find_next_f)(T, char, char *, int *); 79 80 int __board_find_next_rank(T self, char piece, char *file, int *rank) { 81 for (; *file <= 'h'; (*file)++) 82 if (__board_get_at(self, *file, *rank) == piece) 83 return 1; 84 return 0; 85 } 86 87 int __board_find_next_file(T self, char piece, char *file, int *rank) { 88 for (; *rank <= 8; (*rank)++) 89 if (__board_get_at(self, *file, *rank) == piece) 90 return 1; 91 return 0; 92 } 93 94 int __board_find_next(T self, char piece, char *file, int *rank) { 95 for (; *file <= 'h'; (*file)++) { 96 for (; *rank <= 8; (*rank)++) 97 if (__board_get_at(self, *file, *rank) == piece) 98 return 1; 99 *rank = 1; 100 } 101 return 0; 102 } 103 104 void __board_copy(T self, T new) { 105 __grave_copy(self->white, new->white); 106 __grave_copy(self->black, new->black); 107 new->turn = self->turn; 108 for (int i = 0; i < 8; i++) 109 for (int j = 0; j < 8; j++) 110 new->board[i * 8 + j] = self->board[i * 8 + j]; 111 } 112 113 int __board_can_move(T self, char piece, char f_s, int r_s, char f_e, int r_e, 114 int take) { 115 116 char piece_e = __board_get_at(self, f_e, r_e); 117 if (take && !(piece_e != ' ' || (piece == 'P'))) 118 return 0; 119 120 if (toupper(piece) == 'P') { 121 int mul = (piece == 'P') ? 1 : -1; 122 int step = ((piece == 'P' && r_s == 2) || r_s == 7) ? 2 : 1; 123 if (!take) { 124 if (f_s != f_e) 125 return 0; 126 for (int i = 1; i <= step; i++) { 127 char piece_c = __board_get_at(self, f_s, r_s + i * mul); 128 if (piece_c != ' ') 129 return 0; 130 if (r_s + i * mul == r_e) 131 return 1; 132 } 133 } else { 134 return (r_s + mul == r_e && (f_s + 1 == f_e || f_s - 1 == f_e)); 135 } 136 } else { 137 piece = toupper(piece); 138 move_offset_t *move = piece_offset + piece_get_index(piece); 139 140 for (int i = 0; i < move->size; i++) { 141 int rank = r_s, file = f_s; 142 do { 143 file += move->y[i]; 144 rank += move->x[i]; 145 if (rank == r_e && file == f_e) 146 return 1; 147 } while (!move->limited && __board_get_at(self, file, rank) == ' '); 148 } 149 } 150 return 0; 151 } 152 153 G grave_new(void) { 154 G p; 155 NEW(p); 156 p->size = 0; 157 p->value = 0; 158 return p; 159 } 160 161 char Grave_atIndex(G self, int index) { 162 assert(self); 163 return self->arr[index]; 164 } 165 166 int Grave_size(G self) { 167 assert(self); 168 return self->size; 169 } 170 171 G Board_grave(T self, char player) { 172 assert(self); 173 printf("%c\n", player); 174 return (player == 'b') ? self->white : self->black; 175 } 176 177 T Board_new(void) { 178 T board; 179 NEW(board); 180 board->white = grave_new(); 181 board->black = grave_new(); 182 board->board = ALLOC(64 * sizeof(char) + 1); 183 for (int i = 0; i < 8; i++) 184 for (int j = 0; j < 8; j++) 185 board->board[i * 8 + j] = def_board[i][j]; 186 187 board->turn = 0; 188 return board; 189 } 190 191 T Board_from_FEN(char *fen) { 192 T board = Board_new(); 193 194 int j = 0; 195 do { 196 if (isalpha(*fen)) 197 board->board[j++] = *fen; 198 else if (isdigit(*fen)) 199 for (int i = 0; i < *fen - '0'; i++) 200 board->board[j++] = ' '; 201 } while (*fen++ != '\0' && *fen != ' '); 202 return board; 203 } 204 205 void Board_free(T *self) { 206 assert(self); 207 FREE((*self)->board); 208 FREE(*self); 209 } 210 211 T Board_play(T self, char *m, int white) { 212 assert(self); 213 assert(m); 214 215 char mover; 216 mover = (white) ? 'w' : 'b'; 217 218 T new = Board_new(); 219 __board_copy(self, new); 220 221 int (*conv)(int) = (mover == 'w') ? toupper : tolower; 222 int castle_rank = (mover == 'w') ? 1 : 8; 223 224 if (strcmp(m, "O-O") == 0) { 225 __board_set_at(new, 'e', castle_rank, ' '); 226 __board_set_at(new, 'f', castle_rank, conv('R')); 227 __board_set_at(new, 'g', castle_rank, conv('K')); 228 __board_set_at(new, 'h', castle_rank, ' '); 229 return new; 230 } else if (strcmp(m, "O-O-O") == 0) { 231 __board_set_at(new, 'a', castle_rank, ' '); 232 __board_set_at(new, 'c', castle_rank, conv('K')); 233 __board_set_at(new, 'd', castle_rank, conv('R')); 234 __board_set_at(new, 'e', castle_rank, ' '); 235 return new; 236 } else { 237 // Decoding move MESS Start 238 int l = strlen(m); 239 while (m[l - 1] == '+' || m[l - 1] == '#' || m[l - 1] == '!' || 240 m[l - 1] == '?') 241 l--; 242 243 char promoted = 0; 244 if (m[l - 2] == '=') { 245 promoted = conv(m[l - 1]); 246 l -= 2; 247 } 248 249 char file = m[l - 2]; 250 int rank = m[l - 1] - '0'; 251 252 int take = 0; 253 char select = '\0', moved; 254 if (l == 4 && m[1] == 'x') 255 take = 1; 256 else if (l >= 4) { 257 select = m[1]; 258 take = m[2] == 'x'; 259 } 260 261 if (isupper(m[0])) 262 moved = conv(m[0]); 263 else { 264 moved = conv('P'); 265 select = m[0]; 266 } 267 // MESS End 268 269 char file_s = (isalpha(select)) ? select : 'a'; 270 int rank_s = (isdigit(select)) ? select - '0' : 1; 271 272 __board_find_next_f find_f; 273 if (select) 274 find_f = 275 (isalpha(select)) ? __board_find_next_file : __board_find_next_rank; 276 else 277 find_f = __board_find_next; 278 279 while (find_f(self, moved, &file_s, &rank_s)) { 280 if (__board_can_move(self, moved, file_s, rank_s, file, rank, take)) { 281 if (take) 282 __board_send_grave(new, __board_get_at(self, file, rank), mover); 283 __board_set_at(new, file_s, rank_s, ' '); 284 __board_set_at(new, file, rank, promoted ? promoted : moved); 285 return new; 286 } 287 rank_s++; 288 } 289 } 290 291 RAISE(BOARDE_MOVE); 292 return NULL; 293 } 294 295 int piece_get_index(char l) { 296 for (size_t k = 0; k < sizeof(piece_lookup); k++) 297 if (piece_lookup[k] == l) 298 return k; 299 300 return -1; 301 } 302 303 char Board_atIndex(T self, int i, int j) { 304 assert(i >= 0 && i < 9 && j >= 0 && j < 9); 305 return self->board[8 * i + j]; 306 } 307 308 /* GAME */ 309 310 game_T game_new(size_t moves_num) { 311 game_T game = ALLOC(sizeof(*game) + moves_num * sizeof(struct Board_T)); 312 game->moves_num = moves_num; 313 game->display_current = 0; 314 game->buffer_crnt = 0; 315 game->pass = 0; 316 game->fail = 0; 317 memset(game->buffer, '\0', BUFF_SIZE); 318 game->buffer[BUFF_SIZE] = '\0'; 319 320 return game; 321 } 322 323 /* MOVE */ 324 325 char **Move_list(char *pgn, size_t *size) { 326 char *crnt; 327 size_t moves_size = 1, cnt = 0; 328 329 char **moves = malloc(MAX_PLAY * sizeof(*moves)); 330 char *buffer = malloc(1000 * sizeof(char)); 331 strcpy(buffer, pgn); 332 333 moves[0] = "Starting move, empty board!"; 334 for (crnt = strtok(buffer, " "); crnt; 335 crnt = strtok(NULL, " "), cnt = (cnt + 1) % 3) { 336 switch (cnt) { 337 case 0: 338 continue; 339 case 1: 340 case 2: 341 if (strcmp(crnt, "*") != 0) { 342 moves[moves_size] = malloc(MAX_MOVE * sizeof(char)); 343 strcpy(moves[moves_size], crnt); 344 moves_size++; 345 } 346 } 347 } 348 349 if (size) 350 *size = moves_size - 1; 351 352 return moves; 353 } 354 355 #undef G