stellar

Stellar - Chess engine written in C
Log | Files | Refs

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 }