stellar

Stellar - UCI Chess engine written in C++20
git clone git://git.dimitrijedobrota.com/stellar.git
Log | Files | Refs | README | LICENSE

commit ceb66c00e797d8c3042acedd45c8529b11690d60
parent 672abe80ee21dfaf75d2c96e762c58979fe9f05e
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date:   Wed, 28 Sep 2022 12:28:21 +0200

Refactoring CBoard and Piece interface, improve engine

Diffstat:
Ainclude/CBoard.h | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/CBoard.c | 244+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/engine.c | 407+++++++++++++++++--------------------------------------------------------------
3 files changed, 395 insertions(+), 319 deletions(-)

diff --git a/include/CBoard.h b/include/CBoard.h @@ -0,0 +1,63 @@ +#ifndef CBOARD_H +#define CBOARD_H + +#include "attack.h" +#include "utils.h" + +enum enumCastle { WK = 1, WQ = 2, BK = 4, BQ = 8 }; +typedef enum enumCastle eCastle; + +typedef struct Piece_T *Piece_T; + +attack_f Piece_attacks(Piece_T pt); +char Piece_asci(Piece_T pt); +char Piece_code(Piece_T pt); +char *Piece_unicode(Piece_T pt); +eColor Piece_color(Piece_T pt); +ePiece Piece_piece(Piece_T pt); +int Piece_index(Piece_T self); + +Piece_T Piece_fromCode(char code); +Piece_T Piece_fromIndex(int index); +Piece_T Piece_get(ePiece piece, eColor color); + +typedef struct CBoard_T *CBoard_T; + +CBoard_T CBoard_new(void); +void CBoard_copy(CBoard_T self, CBoard_T dest); + +U64 CBoard_colorBB(CBoard_T self, eColor color); +U64 CBoard_pieceBB(CBoard_T self, ePiece piece); +eColor CBoard_side(CBoard_T self); +Square CBoard_enpassant(CBoard_T self); +eCastle CBoard_castle(CBoard_T self); + +void CBoard_enpassant_set(CBoard_T self, Square target); + +void CBoard_piece_pop(CBoard_T self, Piece_T Piece, Square square); +void CBoard_piece_set(CBoard_T self, Piece_T Piece, Square square); +void CBoard_piece_move(CBoard_T self, Piece_T Piece, Square square, + Square target); + +void CBoard_colorBB_pop(CBoard_T self, eColor color, Square target); +void CBoard_colorBB_set(CBoard_T self, eColor color, Square target); +U64 CBoard_colorBB_get(CBoard_T self, eColor color, Square target); + +void CBoard_pieceBB_pop(CBoard_T self, ePiece piece, Square target); +void CBoard_pieceBB_set(CBoard_T self, ePiece piece, Square target); +U64 CBoard_pieceBB_get(CBoard_T self, ePiece piece, Square target); + +void CBoard_castle_pop(CBoard_T self, eCastle castle); +void CBoard_castle_and(CBoard_T self, int exp); + +void CBoard_side_switch(CBoard_T self); +int CBoard_isCheck(CBoard_T self); + +U64 CBoard_getPieceSet(CBoard_T self, Piece_T piece); + +void CBoard_print(CBoard_T self); +CBoard_T CBoard_fromFEN(CBoard_T board, char *fen); + +int CBoard_square_isAttack(CBoard_T self, Square square, eColor side); + +#endif diff --git a/src/CBoard.c b/src/CBoard.c @@ -0,0 +1,244 @@ +#include <ctype.h> +#include <stdio.h> +#include <string.h> + +#include <cii/assert.h> +#include <cii/mem.h> + +#include "CBoard.h" +#include "attack.h" +#include "utils.h" + +// piece representation +struct Piece_T { + ePiece piece; + eColor color; + char code; + char asci; + char *unicode; + attack_f attacks; +}; + +attack_f Piece_attacks(Piece_T pt) { return pt->attacks; } +char Piece_asci(Piece_T pt) { return pt->asci; } +char Piece_code(Piece_T pt) { return pt->code; } +char *Piece_unicode(Piece_T pt) { return pt->unicode; } +eColor Piece_color(Piece_T pt) { return pt->color; } +ePiece Piece_piece(Piece_T pt) { return pt->piece; } +int Piece_index(Piece_T self) { return self->color * 8 + self->piece; } + +// Pieces table [color][piece] +// clang-format off +struct Piece_T Pieces[2][6] = { + { + {.color = WHITE, .code = 'P', .asci = 'P', .unicode = "♙ ", .piece = PAWN, .attacks = get_wpawn_attacks}, + {.color = WHITE, .code = 'N', .asci = 'N', .unicode = "♘ ", .piece = KNIGHT, .attacks = get_knight_attacks}, + {.color = WHITE, .code = 'B', .asci = 'B', .unicode = "♗ ", .piece = BISHOP, .attacks = get_bishop_attacks}, + {.color = WHITE, .code = 'R', .asci = 'R', .unicode = "♖ ", .piece = ROOK, .attacks = get_rook_attacks}, + {.color = WHITE, .code = 'Q', .asci = 'Q', .unicode = "♕ ", .piece = QUEEN, .attacks = get_queen_attacks}, + {.color = WHITE, .code = 'K', .asci = 'K', .unicode = "♔ ", .piece = KING, .attacks = get_king_attacks}, + }, + { + {.color = BLACK, .code = 'p', .asci = 'p', .unicode = "♟ ", .piece = PAWN, .attacks = get_bpawn_attacks}, + {.color = BLACK, .code = 'n', .asci = 'n', .unicode = "♞ ", .piece = KNIGHT, .attacks = get_knight_attacks}, + {.color = BLACK, .code = 'b', .asci = 'b', .unicode = "♝ ", .piece = BISHOP, .attacks = get_bishop_attacks}, + {.color = BLACK, .code = 'r', .asci = 'r', .unicode = "♜ ", .piece = ROOK, .attacks = get_rook_attacks}, + {.color = BLACK, .code = 'q', .asci = 'q', .unicode = "♛ ", .piece = QUEEN, .attacks = get_queen_attacks}, + {.color = BLACK, .code = 'k', .asci = 'k', .unicode = "♚ ", .piece = KING, .attacks = get_king_attacks}, + }, +}; +// clang-format on + +Piece_T Piece_fromCode(char code) { + int color = (isupper(code)) ? WHITE : BLACK; + for (int i = 0; i < 6; i++) + if (Pieces[color][i].code == code) + return &Pieces[color][i]; + return NULL; +} + +Piece_T Piece_fromIndex(int index) { return &Pieces[index / 8][index % 8]; } +Piece_T Piece_get(ePiece piece, eColor color) { return &Pieces[color][piece]; } + +// board representation +struct CBoard_T { + U64 colorBB[2]; + U64 pieceBB[6]; + eColor side; + Square enpassant; + eCastle castle; +}; + +U64 CBoard_colorBB(CBoard_T self, eColor color) { return self->colorBB[color]; } +U64 CBoard_pieceBB(CBoard_T self, ePiece piece) { return self->pieceBB[piece]; } +eColor CBoard_side(CBoard_T self) { return self->side; } +Square CBoard_enpassant(CBoard_T self) { return self->enpassant; } +eCastle CBoard_castle(CBoard_T self) { return self->castle; } + +U64 CBoard_getPieceSet(CBoard_T self, Piece_T piece) { + return self->pieceBB[Piece_piece(piece)] & self->colorBB[Piece_color(piece)]; +} + +CBoard_T CBoard_new(void) { + CBoard_T p; + NEW0(p); + return p; +} + +void CBoard_copy(CBoard_T self, CBoard_T dest) { *dest = *self; } + +void CBoard_enpassant_set(CBoard_T self, Square target) { + self->enpassant = target; +} + +void CBoard_colorBB_pop(CBoard_T self, eColor color, Square target) { + bit_pop(self->colorBB[color], target); +} +void CBoard_colorBB_set(CBoard_T self, eColor color, Square target) { + bit_set(self->colorBB[color], target); +} +U64 CBoard_colorBB_get(CBoard_T self, eColor color, Square target) { + return bit_get(self->colorBB[color], target); +} + +void CBoard_pieceBB_pop(CBoard_T self, ePiece piece, Square target) { + bit_pop(self->pieceBB[piece], target); +} +void CBoard_pieceBB_set(CBoard_T self, ePiece piece, Square target) { + bit_set(self->pieceBB[piece], target); +} +U64 CBoard_pieceBB_get(CBoard_T self, ePiece piece, Square target) { + return bit_get(self->pieceBB[piece], target); +} + +void CBoard_piece_pop(CBoard_T self, Piece_T Piece, Square square) { + bit_pop(self->pieceBB[Piece->piece], square); + bit_pop(self->colorBB[Piece->color], square); +} + +void CBoard_piece_set(CBoard_T self, Piece_T Piece, Square square) { + bit_set(self->pieceBB[Piece->piece], square); + bit_set(self->colorBB[Piece->color], square); +} + +void CBoard_piece_move(CBoard_T self, Piece_T Piece, Square source, + Square target) { + CBoard_piece_pop(self, Piece, source); + CBoard_piece_set(self, Piece, target); +} + +void CBoard_castle_pop(CBoard_T self, eCastle castle) { + bit_pop(self->castle, bit_lsb_index(castle)); +} + +void CBoard_castle_and(CBoard_T self, int exp) { self->castle &= exp; } +void CBoard_side_switch(CBoard_T self) { self->side = !self->side; } + +int CBoard_isCheck(CBoard_T self) { + U64 king = self->pieceBB[KING] & self->colorBB[self->side]; + return CBoard_square_isAttack(self, bit_lsb_index(king), !self->side); +} + +int CBoard_square_isAttack(CBoard_T self, Square square, eColor side) { + U64 occupancy = self->colorBB[WHITE] | self->colorBB[BLACK]; + + for (int i = 0; i < 6; i++) { + if (Pieces[!side][i].attacks(square, occupancy) & self->pieceBB[i] & + self->colorBB[side]) + return 1; + } + + return 0; +} + +void CBoard_print(CBoard_T self) { + for (int rank = 0; rank < 8; rank++) { + for (int file = 0; file < 8; file++) { + Square square = (7 - rank) * 8 + file; + Piece_T piece = NULL; + + int color = -1; + if (bit_get(self->colorBB[WHITE], square)) + color = WHITE; + else if (bit_get(self->colorBB[BLACK], square)) + color = BLACK; + + if (color != -1) { + for (int piece_index = 0; piece_index < 6; piece_index++) { + if (bit_get(self->pieceBB[piece_index], square)) { + piece = &Pieces[color][piece_index]; + break; + } + } + } + + if (!file) + printf(" %d ", 8 - rank); + + printf("%s", (piece) ? Piece_unicode(piece) : ". "); + } + printf("\n"); + } + printf(" A B C D E F G H\n"); + printf(" Side: %s\n", (self->side == WHITE) ? "white" : "black"); + printf("Enpassant: %s\n", square_to_coordinates[self->enpassant]); + printf(" Castling: %c%c%c%c\n", (self->castle & WK) ? 'K' : '-', + (self->castle & WQ) ? 'Q' : '-', (self->castle & BK) ? 'k' : '-', + (self->castle & BQ) ? 'q' : '-'); + printf("\n"); +} + +CBoard_T CBoard_fromFEN(CBoard_T board, char *fen) { + if (!board) + NEW(board); + + memset(board, C64(0), sizeof(*board)); + + board->side = -1; + board->enpassant = no_sq; + board->castle = 0; + + int file = 0, rank = 7; + for (Piece_T piece; *fen != ' '; fen++) { + Square square = rank * 8 + file; + if (isalpha(*fen)) { + if (!(piece = Piece_fromCode(*fen))) + assert(0); + bit_set(board->colorBB[piece->color], square); + bit_set(board->pieceBB[piece->piece], square); + file++; + } else if (isdigit(*fen)) { + file += *fen - '0'; + } else if (*fen == '/') { + file = 0; + rank--; + } else + assert(0); + } + + fen++; + if (*fen == 'w') + board->side = WHITE; + else if (*fen == 'b') + board->side = BLACK; + else + assert(0); + + for (fen += 2; *fen != ' '; fen++) { + switch (*fen) { + case 'K': board->castle |= WK; break; + case 'Q': board->castle |= WQ; break; + case 'k': board->castle |= BK; break; + case 'q': board->castle |= BQ; break; + case '-': break; + default: assert(0); + } + } + + fen++; + if (*fen != '-') { + board->enpassant = (*(fen + 1) - '1') * 8 + (*fen - 'a'); + } + + return board; +} diff --git a/src/engine.c b/src/engine.c @@ -1,8 +1,8 @@ -#include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include "CBoard.h" #include "attack.h" #include "utils.h" @@ -23,59 +23,6 @@ #define cmk_position \ "r2q1rk1/ppp2ppp/2n1bn2/2b1p3/3pP3/3P1NPP/PPP1NPB1/R1BQ1RK1 b - - 0 9 " -// piece representation -typedef struct Piece_T *Piece_T; -struct Piece_T { - ePiece piece; - eColor color; - char code; - char asci; - char *unicode; - attack_f attacks; -}; - -ePiece Piece_piece(Piece_T pt) { return pt->piece; } -eColor Piece_color(Piece_T pt) { return pt->color; } -char Piece_code(Piece_T pt) { return pt->code; } -char Piece_asci(Piece_T pt) { return pt->asci; } -char *Piece_unicode(Piece_T pt) { return pt->unicode; } - -// Pieces table [color][piece] -// clang-format off -struct Piece_T Pieces[2][6] = { - { - {.color = WHITE, .code = 'P', .asci = 'P', .unicode = "♙ ", .piece = PAWN, .attacks = get_wpawn_attacks}, - {.color = WHITE, .code = 'N', .asci = 'N', .unicode = "♘ ", .piece = KNIGHT, .attacks = get_knight_attacks}, - {.color = WHITE, .code = 'B', .asci = 'B', .unicode = "♗ ", .piece = BISHOP, .attacks = get_bishop_attacks}, - {.color = WHITE, .code = 'R', .asci = 'R', .unicode = "♖ ", .piece = ROOK, .attacks = get_rook_attacks}, - {.color = WHITE, .code = 'Q', .asci = 'Q', .unicode = "♕ ", .piece = QUEEN, .attacks = get_queen_attacks}, - {.color = WHITE, .code = 'K', .asci = 'K', .unicode = "♔ ", .piece = KING, .attacks = get_king_attacks}, - }, - { - {.color = BLACK, .code = 'p', .asci = 'p', .unicode = "♟ ", .piece = PAWN, .attacks = get_bpawn_attacks}, - {.color = BLACK, .code = 'n', .asci = 'n', .unicode = "♞ ", .piece = KNIGHT, .attacks = get_knight_attacks}, - {.color = BLACK, .code = 'b', .asci = 'b', .unicode = "♝ ", .piece = BISHOP, .attacks = get_bishop_attacks}, - {.color = BLACK, .code = 'r', .asci = 'r', .unicode = "♜ ", .piece = ROOK, .attacks = get_rook_attacks}, - {.color = BLACK, .code = 'q', .asci = 'q', .unicode = "♛ ", .piece = QUEEN, .attacks = get_queen_attacks}, - {.color = BLACK, .code = 'k', .asci = 'k', .unicode = "♚ ", .piece = KING, .attacks = get_king_attacks}, - }, -}; -// clang-format on -int Piece_index(Piece_T self) { return self->color * 8 + self->piece; } - -Piece_T Piece_fromCode(char code) { - int color = (isupper(code)) ? WHITE : BLACK; - for (int i = 0; i < 6; i++) - if (Pieces[color][i].code == code) - return &Pieces[color][i]; - return NULL; -} - -Piece_T Piece_fromInex(int index) { return &Pieces[index / 8][index % 8]; } - -enum enumCastle { WK = 1, WQ = 2, BK = 4, BQ = 8 }; -typedef enum enumCastle eCastle; - typedef U32 Move; #define Move_encode(source, target, piece, promoted, capture, dbl, enpassant, \ castling) \ @@ -96,8 +43,8 @@ void Move_print(Move move) { printf("%5s %5s %5s %5c %4d %4d %4d %4d\n", square_to_coordinates[Move_source(move)], square_to_coordinates[Move_target(move)], - Piece_fromInex(Move_piece(move))->unicode, - promote ? Piece_fromInex(promote)->asci : 'X', + Piece_unicode(Piece_fromIndex(Move_piece(move))), + promote ? Piece_asci(Piece_fromIndex(promote)) : 'X', Move_capture(move) ? 1 : 0, Move_double(move) ? 1 : 0, Move_enpassant(move) ? 1 : 0, Move_castle(move) ? 1 : 0); } @@ -127,146 +74,55 @@ void MoveList_print(MoveList_T self) { void MoveList_free(MoveList_T *p) { FREE(*p); } -// board representation -typedef struct CBoard_T *CBoard_T; -struct CBoard_T { - U64 colorBB[2]; - U64 pieceBB[6]; - eColor side; - Square enpassant; - eCastle castle; -}; - -U64 CBoard_getPieceSet(CBoard_T self, Piece_T piece) { - return self->pieceBB[Piece_color(piece)] & self->pieceBB[Piece_color(piece)]; -} -U64 CBoard_getWhitePawns(CBoard_T self) { - return self->pieceBB[PAWN] & self->pieceBB[WHITE]; -} -U64 CBoard_getBlackPawns(CBoard_T self) { - return self->pieceBB[PAWN] & self->pieceBB[BLACK]; -} -U64 CBoard_getPawns(CBoard_T self, eColor color) { - return self->pieceBB[PAWN] & self->pieceBB[color]; -} - -/* ... */ - -CBoard_T CBoard_fromFEN(CBoard_T board, char *fen) { - if (!board) - NEW(board); - - memset(board, C64(0), sizeof(*board)); - - board->side = -1; - board->enpassant = no_sq; - board->castle = 0; - - int file = 0, rank = 7; - for (Piece_T piece; *fen != ' '; fen++) { - Square square = rank * 8 + file; - if (isalpha(*fen)) { - if (!(piece = Piece_fromCode(*fen))) - assert(0); - bit_set(board->colorBB[piece->color], square); - bit_set(board->pieceBB[piece->piece], square); - file++; - } else if (isdigit(*fen)) { - file += *fen - '0'; - } else if (*fen == '/') { - file = 0; - rank--; - } else - assert(0); - } - - fen++; - if (*fen == 'w') - board->side = WHITE; - else if (*fen == 'b') - board->side = BLACK; - else - assert(0); - - for (fen += 2; *fen != ' '; fen++) { - switch (*fen) { - case 'K': board->castle |= WK; break; - case 'Q': board->castle |= WQ; break; - case 'k': board->castle |= BK; break; - case 'q': board->castle |= BQ; break; - case '-': break; - default: assert(0); - } - } - - fen++; - if (*fen != '-') { - board->enpassant = (*(fen + 1) - '1') * 8 + (*fen - 'a'); - } - - return board; -} - -int CBoard_square_isAttack(CBoard_T self, Square square, eColor side) { - U64 occupancy = self->colorBB[WHITE] | self->colorBB[BLACK]; - - for (int i = 0; i < 6; i++) { - if (Pieces[!side][i].attacks(square, occupancy) & self->pieceBB[i] & - self->colorBB[side]) - return 1; - } - - return 0; -} - -#define pawn_promotion(color, source) \ +#define pawn_canPromote(color, source) \ ((color == WHITE && source >= a7 && source <= h7) || \ (color == BLACK && source >= a2 && source <= h2)) -#define pawn_start(color, source) \ +#define pawn_onStart(color, source) \ ((color == BLACK && source >= a7 && source <= h7) || \ (color == WHITE && source >= a2 && source <= h2)) #define pawn_promote(source, target, index, capture) \ for (int i = 1; i < 5; i++) { \ - move = Move_encode(source, target, index, Piece_index(&Pieces[color][i]), \ - capture, 0, 0, 0); \ + move = Move_encode(source, target, index, \ + Piece_index(Piece_get(i, color)), capture, 0, 0, 0); \ MoveList_add(moves, move); \ } -MoveList_T CBoard_move_generate(CBoard_T self, MoveList_T moves) { +MoveList_T generate_moves(CBoard_T cboard, MoveList_T moves) { Move move; Square src, tgt; - U64 occupancy = self->colorBB[WHITE] | self->colorBB[BLACK]; - eColor color = self->side; + U64 occupancy = CBoard_colorBB(cboard, WHITE) | CBoard_colorBB(cboard, BLACK); + eColor color = CBoard_side(cboard); if (!moves) moves = MoveList_new(); { // pawn moves - Piece_T Piece = &Pieces[color][PAWN]; + Piece_T Piece = Piece_get(PAWN, color); int index = Piece_index(Piece); - U64 bitboard = self->pieceBB[PAWN] & self->colorBB[color]; + U64 bitboard = CBoard_getPieceSet(cboard, Piece); bitboard_for_each_bit(src, bitboard) { { // quiet int add = (color == WHITE) ? +8 : -8; tgt = src + add; if (tgt > a1 && tgt < h8 && !bit_get(occupancy, tgt)) { - if (pawn_promotion(color, src)) { + if (pawn_canPromote(color, src)) { pawn_promote(src, tgt, index, 0); } else { MoveList_add(moves, Move_encode(src, tgt, index, 0, 0, 0, 0, 0)); // two ahead - if (pawn_start(color, src) && !bit_get(occupancy, tgt += add)) + if (pawn_onStart(color, src) && !bit_get(occupancy, tgt += add)) MoveList_add(moves, Move_encode(src, tgt, index, 0, 0, 1, 0, 0)); } } } { // capture - U64 attack = Piece->attacks(src, occupancy) & self->colorBB[!color]; + U64 attack = Piece_attacks(Piece)(src, occupancy) & + CBoard_colorBB(cboard, !color); bitboard_for_each_bit(tgt, attack) { - if (pawn_promotion(color, src)) { + if (pawn_canPromote(color, src)) { pawn_promote(src, tgt, index, 1); } else { MoveList_add(moves, Move_encode(src, tgt, index, 0, 1, 0, 0, 0)); @@ -275,9 +131,9 @@ MoveList_T CBoard_move_generate(CBoard_T self, MoveList_T moves) { } { // en passant - U64 attack = - Piece->attacks(src, occupancy) & (C64(1) << self->enpassant); - if (self->enpassant != no_sq && attack) + U64 attack = Piece_attacks(Piece)(src, occupancy) & + (C64(1) << CBoard_enpassant(cboard)); + if (CBoard_enpassant(cboard) != no_sq && attack) MoveList_add(moves, Move_encode(src, bit_lsb_index(attack), index, 0, 1, 0, 1, 0)); } @@ -286,12 +142,13 @@ MoveList_T CBoard_move_generate(CBoard_T self, MoveList_T moves) { // All piece move for (int piece = 1; piece < 6; piece++) { - Piece_T Piece = &Pieces[color][piece]; - U64 bitboard = self->pieceBB[piece] & self->colorBB[color]; + Piece_T Piece = Piece_get(piece, color); + U64 bitboard = CBoard_getPieceSet(cboard, Piece); bitboard_for_each_bit(src, bitboard) { - U64 attack = Piece->attacks(src, occupancy) & ~self->colorBB[color]; + U64 attack = + Piece_attacks(Piece)(src, occupancy) & ~CBoard_colorBB(cboard, color); bitboard_for_each_bit(tgt, attack) { - int take = bit_get(self->colorBB[!color], tgt); + int take = bit_get(CBoard_colorBB(cboard, !color), tgt); MoveList_add( moves, Move_encode(src, tgt, Piece_index(Piece), 0, take, 0, 0, 0)); } @@ -301,33 +158,33 @@ MoveList_T CBoard_move_generate(CBoard_T self, MoveList_T moves) { // Castling { if (color == WHITE) { - int index = Piece_index(&Pieces[WHITE][KING]); - if (self->castle & WK) { + int index = Piece_index(Piece_get(KING, WHITE)); + if (CBoard_castle(cboard) & WK) { if (!bit_get(occupancy, f1) && !bit_get(occupancy, g1)) - if (!CBoard_square_isAttack(self, e1, BLACK) && - !CBoard_square_isAttack(self, f1, BLACK)) + if (!CBoard_square_isAttack(cboard, e1, BLACK) && + !CBoard_square_isAttack(cboard, f1, BLACK)) MoveList_add(moves, Move_encode(e1, g1, index, 0, 0, 0, 0, 1)); } - if (self->castle & WQ) { + if (CBoard_castle(cboard) & WQ) { if (!bit_get(occupancy, d1) && !bit_get(occupancy, c1) && !bit_get(occupancy, b1)) - if (!CBoard_square_isAttack(self, e1, BLACK) && - !CBoard_square_isAttack(self, d1, BLACK)) + if (!CBoard_square_isAttack(cboard, e1, BLACK) && + !CBoard_square_isAttack(cboard, d1, BLACK)) MoveList_add(moves, Move_encode(e1, c1, index, 0, 0, 0, 0, 1)); } } else { - int index = Piece_index(&Pieces[BLACK][KING]); - if (self->castle & BK) { + int index = Piece_index(Piece_get(KING, BLACK)); + if (CBoard_castle(cboard) & BK) { if (!bit_get(occupancy, f8) && !bit_get(occupancy, g8)) - if (!CBoard_square_isAttack(self, e8, WHITE) && - !CBoard_square_isAttack(self, f8, WHITE)) + if (!CBoard_square_isAttack(cboard, e8, WHITE) && + !CBoard_square_isAttack(cboard, f8, WHITE)) MoveList_add(moves, Move_encode(e8, g8, index, 0, 0, 0, 0, 1)); } - if (self->castle & BQ) { + if (CBoard_castle(cboard) & BQ) { if (!bit_get(occupancy, d8) && !bit_get(occupancy, c8) && !bit_get(occupancy, b8)) - if (!CBoard_square_isAttack(self, e8, WHITE) && - !CBoard_square_isAttack(self, d8, WHITE)) + if (!CBoard_square_isAttack(cboard, e8, WHITE) && + !CBoard_square_isAttack(cboard, d8, WHITE)) MoveList_add(moves, Move_encode(e8, c8, index, 0, 0, 0, 0, 1)); } } @@ -336,22 +193,6 @@ MoveList_T CBoard_move_generate(CBoard_T self, MoveList_T moves) { return moves; } -void CBoard_piece_pop(CBoard_T self, Piece_T Piece, Square square) { - bit_pop(self->pieceBB[Piece->piece], square); - bit_pop(self->colorBB[Piece->color], square); -} - -void CBoard_piece_set(CBoard_T self, Piece_T Piece, Square square) { - bit_set(self->pieceBB[Piece->piece], square); - bit_set(self->colorBB[Piece->color], square); -} - -void CBoard_piece_move(CBoard_T self, Piece_T Piece, Square source, - Square target) { - CBoard_piece_pop(self, Piece, source); - CBoard_piece_set(self, Piece, target); -} - // clang-format off const int castling_rights[64] = { 13, 15, 15, 15, 12, 15, 15, 14, @@ -365,94 +206,78 @@ const int castling_rights[64] = { }; // clang-format on -int CBoard_move_make(CBoard_T self, Move move, int flag) { +int make_move(CBoard_T self, Move move, int flag) { if (flag == 0) { Square source = Move_source(move); Square target = Move_target(move); - Piece_T Piece = Piece_fromInex(Move_piece(move)); + Piece_T Piece = Piece_fromIndex(Move_piece(move)); CBoard_piece_move(self, Piece, source, target); if (Move_capture(move)) { - bit_pop(self->colorBB[!Piece->color], target); + CBoard_colorBB_pop(self, !Piece_color(Piece), target); ePiece i; for (i = 0; i < 6; i++) { - if (i != Piece->piece && bit_get(self->pieceBB[i], target)) { - bit_pop(self->pieceBB[i], target); + if (i != Piece_piece(Piece) && CBoard_pieceBB_get(self, i, target)) { + CBoard_pieceBB_pop(self, i, target); break; } } - if (i == ROOK) { - if (self->side != WHITE) { - if (target == h1) - bit_pop(self->castle, 0); - else if (target == a1) - bit_pop(self->castle, 1); - } else { - if (self->side == WHITE) { - if (target == h8) - bit_pop(self->castle, 2); - else if (target == a8) - bit_pop(self->castle, 3); - } - } - } } if (Move_promote(move)) { - Piece_T Promote = Piece_fromInex(Move_promote(move)); - bit_pop(self->pieceBB[Piece->piece], target); - bit_set(self->pieceBB[Promote->piece], target); + Piece_T Promote = Piece_fromIndex(Move_promote(move)); + CBoard_pieceBB_pop(self, Piece_piece(Piece), target); + CBoard_pieceBB_set(self, Piece_piece(Promote), target); } if (Move_enpassant(move)) { - if (Piece->color == WHITE) - CBoard_piece_pop(self, &Pieces[!Piece->color][PAWN], target - 8); + if (Piece_color(Piece) == WHITE) + CBoard_piece_pop(self, Piece_get(PAWN, !Piece_color(Piece)), + target - 8); else - CBoard_piece_pop(self, &Pieces[!Piece->color][PAWN], target + 8); + CBoard_piece_pop(self, Piece_get(PAWN, !Piece_color(Piece)), + target + 8); } if (Move_double(move)) - self->enpassant = target + (Piece->color == WHITE ? -8 : +8); + CBoard_enpassant_set(self, + target + (Piece_color(Piece) == WHITE ? -8 : +8)); else - self->enpassant = no_sq; + CBoard_enpassant_set(self, no_sq); if (Move_castle(move)) { - if (self->side == WHITE) { - Piece_T Rook = &Pieces[WHITE][ROOK]; + if (CBoard_side(self) == WHITE) { + Piece_T Rook = Piece_get(ROOK, WHITE); if (target == g1) CBoard_piece_move(self, Rook, h1, f1); else CBoard_piece_move(self, Rook, a1, d1); - bit_pop(self->castle, 0); - bit_pop(self->castle, 1); + CBoard_castle_pop(self, WK); + CBoard_castle_pop(self, WQ); } else { - Piece_T Rook = &Pieces[BLACK][ROOK]; + Piece_T Rook = Piece_get(ROOK, BLACK); if (target == g8) CBoard_piece_move(self, Rook, h8, f8); else CBoard_piece_move(self, Rook, a8, d8); - bit_pop(self->castle, 2); - bit_pop(self->castle, 3); + CBoard_castle_pop(self, BK); + CBoard_castle_pop(self, BQ); } } - self->castle &= castling_rights[source]; - self->castle &= castling_rights[target]; - - if (!CBoard_square_isAttack( - self, - bit_lsb_index(self->pieceBB[KING] & self->colorBB[self->side]), - !self->side)) { - self->side = !self->side; + CBoard_castle_and(self, castling_rights[source]); + CBoard_castle_and(self, castling_rights[target]); + if (!CBoard_isCheck(self)) { + CBoard_side_switch(self); return 1; } else return 0; } else { if (Move_capture(move)) { - CBoard_move_make(self, move, 0); + make_move(self, move, 0); return 1; } else return 0; @@ -461,107 +286,46 @@ int CBoard_move_make(CBoard_T self, Move move, int flag) { return 0; } -void CBoard_print(CBoard_T self) { - for (int rank = 0; rank < 8; rank++) { - for (int file = 0; file < 8; file++) { - Square square = (7 - rank) * 8 + file; - Piece_T piece = NULL; - - int color = -1; - if (bit_get(self->colorBB[WHITE], square)) - color = WHITE; - else if (bit_get(self->colorBB[BLACK], square)) - color = BLACK; - - if (color != -1) { - for (int piece_index = 0; piece_index < 6; piece_index++) { - if (bit_get(self->pieceBB[piece_index], square)) { - piece = &Pieces[color][piece_index]; - break; - } - } - } - - if (!file) - printf(" %d ", 8 - rank); - - printf("%s", (piece) ? Piece_unicode(piece) : ". "); - } - printf("\n"); - } - printf(" A B C D E F G H\n"); - printf(" Side: %s\n", (self->side == WHITE) ? "white" : "black"); - printf("Enpassant: %s\n", square_to_coordinates[self->enpassant]); - printf(" Castling: %c%c%c%c\n", (self->castle & WK) ? 'K' : '-', - (self->castle & WQ) ? 'Q' : '-', (self->castle & BK) ? 'k' : '-', - (self->castle & BQ) ? 'q' : '-'); - printf("\n"); -} - -void CBoard_print_attacked(CBoard_T self, eColor side) { - for (int rank = 0; rank < 8; rank++) { - for (int file = 0; file < 8; file++) { - Square square = (7 - rank) * 8 + file; - - if (!file) - printf(" %d ", 8 - rank); - - printf("%d ", CBoard_square_isAttack(self, square, side)); - } - printf("\n"); - } - printf(" A B C D E F G H\n"); - printf("\n"); -} - -void init_all() { - init_leapers_attacks(); - init_sliders_attacks(); -} - long nodes = 0; struct MoveList_T moveList[10]; -void CBoard_perft_driver(CBoard_T self, int depth) { +void perft_driver(CBoard_T self, int depth) { if (depth == 0) { nodes++; return; } + CBoard_T backup = CBoard_new(); MoveList_T moves; - moves = CBoard_move_generate(self, &moveList[depth]); + moves = generate_moves(self, &moveList[depth]); - for (int i = 0; i < moves->count; i++) { - struct CBoard_T backup = *self; - if (!CBoard_move_make(self, moves->moves[i], 0)) { - *self = backup; + for (int i = 0; i < moves->count; i++, CBoard_copy(backup, self)) { + CBoard_copy(self, backup); + if (!make_move(self, moves->moves[i], 0)) continue; - } - CBoard_perft_driver(self, depth - 1); - *self = backup; + perft_driver(self, depth - 1); } moveList[depth].count = 0; } -void CBoard_perft_test(CBoard_T self, int depth) { +void perft_test(CBoard_T self, int depth) { + CBoard_T backup = CBoard_new(); + printf("\n Performance test\n\n"); MoveList_T moves; - moves = CBoard_move_generate(self, &moveList[depth]); + moves = generate_moves(self, &moveList[depth]); long start = get_time_ms(); - for (int i = 0; i < moves->count; i++) { - struct CBoard_T backup = *self; - if (!CBoard_move_make(self, moves->moves[i], 0)) { - *self = backup; + for (int i = 0; i < moves->count; i++, CBoard_copy(backup, self)) { + CBoard_copy(self, backup); + if (!make_move(self, moves->moves[i], 0)) continue; - } long cummulative_nodes = nodes; - CBoard_perft_driver(self, depth - 1); + perft_driver(self, depth - 1); long old_nodes = nodes - cummulative_nodes; - *self = backup; printf("%s%s: %ld\n", square_to_coordinates[Move_source(moves->moves[i])], square_to_coordinates[Move_target(moves->moves[i])], old_nodes); } @@ -576,11 +340,16 @@ void CBoard_perft_test(CBoard_T self, int depth) { printf(" Time: %ld\n\n", get_time_ms() - start); } +void init_all() { + init_leapers_attacks(); + init_sliders_attacks(); +} + int main(void) { init_all(); CBoard_T board = CBoard_fromFEN(NULL, tricky_position); - CBoard_perft_test(board, 4); + perft_test(board, 4); return 0; }