CBoard.c (9181B)
1 #include <ctype.h> 2 #include <stdio.h> 3 #include <string.h> 4 5 #include <cul/assert.h> 6 #include <cul/mem.h> 7 8 #include "CBoard.h" 9 #include "attack.h" 10 #include "utils.h" 11 12 U64 CBoard_pieceBB_get(CBoard_T self, ePiece piece, Square target); 13 14 // PIECE 15 struct Piece_T { 16 ePiece piece; 17 eColor color; 18 char code; 19 char asci; 20 char *unicode; 21 attack_f attacks; 22 }; 23 24 // clang-format off 25 struct Piece_T Pieces[2][6] = { 26 { 27 [PAWN] = {.color = WHITE, .code = 'P', .asci = 'P', .unicode = "♙ ", .piece = PAWN, .attacks = get_wpawn_attacks}, 28 [KNIGHT] = {.color = WHITE, .code = 'N', .asci = 'N', .unicode = "♘ ", .piece = KNIGHT, .attacks = get_knight_attacks}, 29 [BISHOP] = {.color = WHITE, .code = 'B', .asci = 'B', .unicode = "♗ ", .piece = BISHOP, .attacks = get_bishop_attacks}, 30 [ROOK] = {.color = WHITE, .code = 'R', .asci = 'R', .unicode = "♖ ", .piece = ROOK, .attacks = get_rook_attacks}, 31 [QUEEN] = {.color = WHITE, .code = 'Q', .asci = 'Q', .unicode = "♕ ", .piece = QUEEN, .attacks = get_queen_attacks}, 32 [KING] = {.color = WHITE, .code = 'K', .asci = 'K', .unicode = "♔ ", .piece = KING, .attacks = get_king_attacks}, 33 }, 34 { 35 [PAWN] = {.color = BLACK, .code = 'p', .asci = 'p', .unicode = "♟ ", .piece = PAWN, .attacks = get_bpawn_attacks}, 36 [KNIGHT] = {.color = BLACK, .code = 'n', .asci = 'n', .unicode = "♞ ", .piece = KNIGHT, .attacks = get_knight_attacks}, 37 [BISHOP] = {.color = BLACK, .code = 'b', .asci = 'b', .unicode = "♝ ", .piece = BISHOP, .attacks = get_bishop_attacks}, 38 [ROOK] = {.color = BLACK, .code = 'r', .asci = 'r', .unicode = "♜ ", .piece = ROOK, .attacks = get_rook_attacks}, 39 [QUEEN] = {.color = BLACK, .code = 'q', .asci = 'q', .unicode = "♛ ", .piece = QUEEN, .attacks = get_queen_attacks}, 40 [KING] = {.color = BLACK, .code = 'k', .asci = 'k', .unicode = "♚ ", .piece = KING, .attacks = get_king_attacks}, 41 }, 42 }; 43 // clang-format on 44 45 attack_f Piece_attacks(Piece_T self) { return self->attacks; } 46 char Piece_asci(Piece_T self) { return self->asci; } 47 char Piece_code(Piece_T self) { return self->code; } 48 char *Piece_unicode(Piece_T self) { return self->unicode; } 49 eColor Piece_color(Piece_T self) { return self->color; } 50 ePiece Piece_piece(Piece_T self) { return self->piece; } 51 int Piece_index(Piece_T self) { return self->color * 8 + self->piece; } 52 53 Piece_T Piece_fromCode(char code) { 54 int color = (isupper(code)) ? WHITE : BLACK; 55 for (int i = 0; i < 6; i++) 56 if (Pieces[color][i].code == code) return &Pieces[color][i]; 57 return NULL; 58 } 59 60 ePiece Piece_piece_fromCode(int index) { 61 return Pieces[WHITE][index % 8].piece; 62 } 63 64 Piece_T Piece_fromIndex(int index) { return &Pieces[index / 8][index % 8]; } 65 Piece_T Piece_get(ePiece piece, eColor color) { return &Pieces[color][piece]; } 66 67 // CBOARD 68 struct CBoard_T { 69 U64 colorBB[2]; 70 U64 pieceBB[6]; 71 eColor side; 72 Square enpassant; 73 eCastle castle; 74 }; 75 76 CBoard_T CBoard_new(void) { 77 CBoard_T p; 78 NEW0(p); 79 return p; 80 } 81 82 void CBoard_free(CBoard_T *p) { FREE(*p); } 83 84 void CBoard_copy(CBoard_T self, CBoard_T dest) { *dest = *self; } 85 86 Square CBoard_enpassant(CBoard_T self) { return self->enpassant; } 87 eCastle CBoard_castle(CBoard_T self) { return self->castle; } 88 eColor CBoard_side(CBoard_T self) { return self->side; } 89 U64 CBoard_colorBB(CBoard_T self, eColor color) { return self->colorBB[color]; } 90 U64 CBoard_pieceBB(CBoard_T self, ePiece piece) { return self->pieceBB[piece]; } 91 U64 CBoard_occupancy(CBoard_T self) { 92 return self->colorBB[WHITE] | self->colorBB[BLACK]; 93 } 94 95 U64 CBoard_pieceBB_get(CBoard_T self, ePiece piece, Square target) { 96 return bit_get(self->pieceBB[piece], target); 97 } 98 99 U64 CBoard_pieceSet(CBoard_T self, Piece_T piece) { 100 return self->pieceBB[Piece_piece(piece)] & 101 self->colorBB[Piece_color(piece)]; 102 } 103 104 void CBoard_enpassant_set(CBoard_T self, Square target) { 105 self->enpassant = target; 106 } 107 108 void CBoard_colorBB_pop(CBoard_T self, eColor color, Square target) { 109 bit_pop(self->colorBB[color], target); 110 } 111 void CBoard_colorBB_set(CBoard_T self, eColor color, Square target) { 112 bit_set(self->colorBB[color], target); 113 } 114 U64 CBoard_colorBB_get(CBoard_T self, eColor color, Square target) { 115 return bit_get(self->colorBB[color], target); 116 } 117 118 int CBoard_piece_get(CBoard_T self, Square square) { 119 for (int i = 0; i < 6; i++) 120 if (bit_get(self->pieceBB[i], square)) return i; 121 return -1; 122 } 123 124 void CBoard_piece_pop(CBoard_T self, Piece_T Piece, Square square) { 125 bit_pop(self->pieceBB[Piece->piece], square); 126 bit_pop(self->colorBB[Piece->color], square); 127 } 128 129 void CBoard_piece_set(CBoard_T self, Piece_T Piece, Square square) { 130 bit_set(self->pieceBB[Piece->piece], square); 131 bit_set(self->colorBB[Piece->color], square); 132 } 133 134 void CBoard_piece_move(CBoard_T self, Piece_T Piece, Square source, 135 Square target) { 136 CBoard_piece_pop(self, Piece, source); 137 CBoard_piece_set(self, Piece, target); 138 } 139 140 U64 CBoard_piece_attacks(CBoard_T self, Piece_T Piece, Square src) { 141 return Piece_attacks(Piece)(src, CBoard_occupancy(self)); 142 } 143 144 void CBoard_piece_capture(CBoard_T self, Piece_T Piece, Piece_T Taken, 145 Square source, Square target) { 146 CBoard_piece_pop(self, Piece, source); 147 if (Taken) CBoard_piece_pop(self, Taken, target); 148 CBoard_piece_set(self, Piece, target); 149 } 150 151 void CBoard_castle_pop(CBoard_T self, eCastle castle) { 152 bit_pop(self->castle, bit_lsb_index(castle)); 153 } 154 155 void CBoard_castle_and(CBoard_T self, int exp) { self->castle &= exp; } 156 void CBoard_side_switch(CBoard_T self) { self->side = !self->side; } 157 158 int CBoard_isCheck(CBoard_T self) { 159 U64 king = self->pieceBB[KING] & self->colorBB[self->side]; 160 return CBoard_square_isAttack(self, bit_lsb_index(king), !self->side); 161 } 162 int CBoard_square_isOccupied(CBoard_T self, Square square) { 163 return bit_get(CBoard_occupancy(self), square); 164 } 165 166 int CBoard_square_isAttack(CBoard_T self, Square square, eColor side) { 167 U64 occupancy = self->colorBB[WHITE] | self->colorBB[BLACK]; 168 169 for (int i = 0; i < 6; i++) { 170 if (Pieces[!side][i].attacks(square, occupancy) & self->pieceBB[i] & 171 self->colorBB[side]) 172 return 1; 173 } 174 175 return 0; 176 } 177 178 Piece_T CBoard_square_piece(CBoard_T self, Square square, eColor color) { 179 for (ePiece i = 0; i < 6; i++) 180 if (CBoard_pieceBB_get(self, i, square)) return Piece_get(i, color); 181 return NULL; 182 } 183 184 void CBoard_print(CBoard_T self) { 185 for (int rank = 0; rank < 8; rank++) { 186 for (int file = 0; file < 8; file++) { 187 Square square = (7 - rank) * 8 + file; 188 Piece_T piece = NULL; 189 190 int color = -1; 191 if (bit_get(self->colorBB[WHITE], square)) 192 color = WHITE; 193 else if (bit_get(self->colorBB[BLACK], square)) 194 color = BLACK; 195 196 if (color != -1) { 197 for (int piece_index = 0; piece_index < 6; piece_index++) { 198 if (bit_get(self->pieceBB[piece_index], square)) { 199 piece = &Pieces[color][piece_index]; 200 break; 201 } 202 } 203 } 204 205 if (!file) printf(" %d ", 8 - rank); 206 207 printf("%s", (piece) ? Piece_unicode(piece) : ". "); 208 } 209 printf("\n"); 210 } 211 printf(" A B C D E F G H\n"); 212 printf(" Side: %s\n", (self->side == WHITE) ? "white" : "black"); 213 printf("Enpassant: %s\n", square_to_coordinates[self->enpassant]); 214 printf(" Castling: %c%c%c%c\n", (self->castle & WK) ? 'K' : '-', 215 (self->castle & WQ) ? 'Q' : '-', (self->castle & BK) ? 'k' : '-', 216 (self->castle & BQ) ? 'q' : '-'); 217 printf("\n"); 218 } 219 220 CBoard_T CBoard_fromFEN(CBoard_T board, char *fen) { 221 if (!board) NEW(board); 222 223 memset(board, 0, sizeof(*board)); 224 225 board->side = -1; 226 board->enpassant = no_sq; 227 board->castle = 0; 228 229 int file = 0, rank = 7; 230 for (Piece_T piece; *fen != ' '; fen++) { 231 Square square = rank * 8 + file; 232 if (isalpha(*fen)) { 233 if (!(piece = Piece_fromCode(*fen))) assert(0); 234 bit_set(board->colorBB[piece->color], square); 235 bit_set(board->pieceBB[piece->piece], square); 236 file++; 237 } else if (isdigit(*fen)) { 238 file += *fen - '0'; 239 } else if (*fen == '/') { 240 file = 0; 241 rank--; 242 } else 243 assert(0); 244 } 245 246 fen++; 247 if (*fen == 'w') 248 board->side = WHITE; 249 else if (*fen == 'b') 250 board->side = BLACK; 251 else 252 assert(0); 253 254 for (fen += 2; *fen != ' '; fen++) { 255 switch (*fen) { 256 case 'K': 257 board->castle |= WK; 258 break; 259 case 'Q': 260 board->castle |= WQ; 261 break; 262 case 'k': 263 board->castle |= BK; 264 break; 265 case 'q': 266 board->castle |= BQ; 267 break; 268 case '-': 269 break; 270 default: 271 assert(0); 272 } 273 } 274 275 fen++; 276 if (*fen != '-') { 277 board->enpassant = coordinates_to_square(fen); 278 } 279 280 return board; 281 }