stellar

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

commit a5b0115a1f2e854c94cacdddc0640bf74f257d36
parent ceb66c00e797d8c3042acedd45c8529b11690d60
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date:   Wed, 28 Sep 2022 18:10:46 +0200

More Refactoring

Diffstat:
Minclude/CBoard.h | 48++++++++++++++++++++++--------------------------
Minclude/attack.h | 2--
Minclude/utils.h | 2++
Msrc/CBoard.c | 83+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Msrc/engine.c | 138+++++++++++++++++++++++++++++++------------------------------------------------
5 files changed, 130 insertions(+), 143 deletions(-)

diff --git a/include/CBoard.h b/include/CBoard.h @@ -1,7 +1,6 @@ #ifndef CBOARD_H #define CBOARD_H -#include "attack.h" #include "utils.h" enum enumCastle { WK = 1, WQ = 2, BK = 4, BQ = 8 }; @@ -9,13 +8,12 @@ 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); +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); @@ -27,37 +25,35 @@ CBoard_T CBoard_new(void); void CBoard_copy(CBoard_T self, CBoard_T dest); U64 CBoard_colorBB(CBoard_T self, eColor color); +U64 CBoard_occupancy(CBoard_T self); 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); +eColor CBoard_side(CBoard_T self); -void CBoard_enpassant_set(CBoard_T self, Square target); +Square CBoard_enpassant(CBoard_T self); +void CBoard_enpassant_set(CBoard_T self, Square target); +U64 CBoard_pieceSet(CBoard_T self, Piece_T piece); +U64 CBoard_piece_attacks(CBoard_T self, Piece_T Piece, Square src); +void CBoard_piece_capture(CBoard_T self, Piece_T Piece, Square source, Square target); +void CBoard_piece_move(CBoard_T self, Piece_T Piece, Square square, 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); +U64 CBoard_colorBB_get(CBoard_T self, eColor color, 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_castle_pop(CBoard_T self, eCastle castle); -void CBoard_side_switch(CBoard_T self); -int CBoard_isCheck(CBoard_T self); - -U64 CBoard_getPieceSet(CBoard_T self, Piece_T piece); +Piece_T CBoard_square_piece(CBoard_T self, Square square, eColor side); +int CBoard_square_isAttack(CBoard_T self, Square square, eColor side); +int CBoard_square_isOccupied(CBoard_T self, Square square); -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); +int CBoard_isCheck(CBoard_T self); +void CBoard_print(CBoard_T self); +void CBoard_side_switch(CBoard_T self); #endif diff --git a/include/attack.h b/include/attack.h @@ -3,8 +3,6 @@ #include "utils.h" -typedef U64 (*attack_f)(Square square, U64 occupancy); - void init_leapers_attacks(void); void init_sliders_attacks(void); diff --git a/include/utils.h b/include/utils.h @@ -70,4 +70,6 @@ typedef enum enumPiece ePiece; int get_time_ms(void); +typedef U64 (*attack_f)(Square square, U64 occupancy); + #endif diff --git a/src/CBoard.c b/src/CBoard.c @@ -9,7 +9,9 @@ #include "attack.h" #include "utils.h" -// piece representation +U64 CBoard_pieceBB_get(CBoard_T self, ePiece piece, Square target); + +// PIECE struct Piece_T { ePiece piece; eColor color; @@ -19,15 +21,6 @@ struct Piece_T { 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] = { { @@ -49,6 +42,14 @@ struct Piece_T Pieces[2][6] = { }; // clang-format on +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; } + Piece_T Piece_fromCode(char code) { int color = (isupper(code)) ? WHITE : BLACK; for (int i = 0; i < 6; i++) @@ -60,7 +61,7 @@ Piece_T Piece_fromCode(char code) { 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 +// CBOARD struct CBoard_T { U64 colorBB[2]; U64 pieceBB[6]; @@ -69,16 +70,6 @@ struct CBoard_T { 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); @@ -87,6 +78,23 @@ CBoard_T CBoard_new(void) { void CBoard_copy(CBoard_T self, CBoard_T dest) { *dest = *self; } +Square CBoard_enpassant(CBoard_T self) { return self->enpassant; } +eCastle CBoard_castle(CBoard_T self) { return self->castle; } +eColor CBoard_side(CBoard_T self) { return self->side; } +U64 CBoard_colorBB(CBoard_T self, eColor color) { return self->colorBB[color]; } +U64 CBoard_pieceBB(CBoard_T self, ePiece piece) { return self->pieceBB[piece]; } +U64 CBoard_occupancy(CBoard_T self) { + return self->colorBB[WHITE] | self->colorBB[BLACK]; +} + +U64 CBoard_pieceBB_get(CBoard_T self, ePiece piece, Square target) { + return bit_get(self->pieceBB[piece], target); +} + +U64 CBoard_pieceSet(CBoard_T self, Piece_T piece) { + return self->pieceBB[Piece_piece(piece)] & self->colorBB[Piece_color(piece)]; +} + void CBoard_enpassant_set(CBoard_T self, Square target) { self->enpassant = target; } @@ -101,16 +109,6 @@ 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); @@ -127,6 +125,19 @@ void CBoard_piece_move(CBoard_T self, Piece_T Piece, Square source, CBoard_piece_set(self, Piece, target); } +U64 CBoard_piece_attacks(CBoard_T self, Piece_T Piece, Square src) { + return Piece_attacks(Piece)(src, CBoard_occupancy(self)); +} + +void CBoard_piece_capture(CBoard_T self, Piece_T Piece, Square source, + Square target) { + Piece_T taken; + CBoard_piece_pop(self, Piece, source); + if ((taken = CBoard_square_piece(self, target, !self->side))) + CBoard_piece_pop(self, taken, target); + CBoard_piece_set(self, Piece, target); +} + void CBoard_castle_pop(CBoard_T self, eCastle castle) { bit_pop(self->castle, bit_lsb_index(castle)); } @@ -138,6 +149,9 @@ 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_isOccupied(CBoard_T self, Square square) { + return bit_get(CBoard_occupancy(self), square); +} int CBoard_square_isAttack(CBoard_T self, Square square, eColor side) { U64 occupancy = self->colorBB[WHITE] | self->colorBB[BLACK]; @@ -151,6 +165,13 @@ int CBoard_square_isAttack(CBoard_T self, Square square, eColor side) { return 0; } +Piece_T CBoard_square_piece(CBoard_T self, Square square, eColor color) { + for (ePiece i = 0; i < 6; i++) + if (CBoard_pieceBB_get(self, i, square)) + return Piece_get(i, color); + return NULL; +} + void CBoard_print(CBoard_T self) { for (int rank = 0; rank < 8; rank++) { for (int file = 0; file < 8; file++) { diff --git a/src/engine.c b/src/engine.c @@ -92,7 +92,6 @@ void MoveList_free(MoveList_T *p) { FREE(*p); } MoveList_T generate_moves(CBoard_T cboard, MoveList_T moves) { Move move; Square src, tgt; - U64 occupancy = CBoard_colorBB(cboard, WHITE) | CBoard_colorBB(cboard, BLACK); eColor color = CBoard_side(cboard); if (!moves) @@ -106,20 +105,21 @@ MoveList_T generate_moves(CBoard_T cboard, MoveList_T moves) { { // quiet int add = (color == WHITE) ? +8 : -8; tgt = src + add; - if (tgt > a1 && tgt < h8 && !bit_get(occupancy, tgt)) { + if (tgt > a1 && tgt < h8 && !CBoard_square_isOccupied(cboard, tgt)) { 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_onStart(color, src) && !bit_get(occupancy, tgt += add)) + if (pawn_onStart(color, src) && + !CBoard_square_isOccupied(cboard, tgt += add)) MoveList_add(moves, Move_encode(src, tgt, index, 0, 0, 1, 0, 0)); } } } { // capture - U64 attack = Piece_attacks(Piece)(src, occupancy) & + U64 attack = CBoard_piece_attacks(cboard, Piece, src) & CBoard_colorBB(cboard, !color); bitboard_for_each_bit(tgt, attack) { if (pawn_canPromote(color, src)) { @@ -131,11 +131,11 @@ MoveList_T generate_moves(CBoard_T cboard, MoveList_T moves) { } { // en passant - 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)); + if (CBoard_enpassant(cboard) != no_sq && + CBoard_piece_attacks(cboard, Piece, src) & + (C64(1) << CBoard_enpassant(cboard))) + MoveList_add(moves, Move_encode(src, CBoard_enpassant(cboard), index, + 0, 1, 0, 1, 0)); } } } @@ -145,8 +145,8 @@ MoveList_T generate_moves(CBoard_T cboard, MoveList_T moves) { Piece_T Piece = Piece_get(piece, color); U64 bitboard = CBoard_getPieceSet(cboard, Piece); bitboard_for_each_bit(src, bitboard) { - U64 attack = - Piece_attacks(Piece)(src, occupancy) & ~CBoard_colorBB(cboard, color); + U64 attack = CBoard_piece_attacks(cboard, Piece, src) & + ~CBoard_colorBB(cboard, color); bitboard_for_each_bit(tgt, attack) { int take = bit_get(CBoard_colorBB(cboard, !color), tgt); MoveList_add( @@ -160,14 +160,16 @@ MoveList_T generate_moves(CBoard_T cboard, MoveList_T moves) { if (color == WHITE) { 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_isOccupied(cboard, f1) && + !CBoard_square_isOccupied(cboard, g1)) 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 (CBoard_castle(cboard) & WQ) { - if (!bit_get(occupancy, d1) && !bit_get(occupancy, c1) && - !bit_get(occupancy, b1)) + if (!CBoard_square_isOccupied(cboard, d1) && + !CBoard_square_isOccupied(cboard, c1) && + !CBoard_square_isOccupied(cboard, b1)) 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)); @@ -175,14 +177,16 @@ MoveList_T generate_moves(CBoard_T cboard, MoveList_T moves) { } else { 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_isOccupied(cboard, f8) && + !CBoard_square_isOccupied(cboard, g8)) 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 (CBoard_castle(cboard) & BQ) { - if (!bit_get(occupancy, d8) && !bit_get(occupancy, c8) && - !bit_get(occupancy, b8)) + if (!CBoard_square_isOccupied(cboard, d8) && + !CBoard_square_isOccupied(cboard, c8) && + !CBoard_square_isOccupied(cboard, b8)) 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)); @@ -206,84 +210,58 @@ const int castling_rights[64] = { }; // clang-format on -int make_move(CBoard_T self, Move move, int flag) { +int make_move(CBoard_T cboard, Move move, int flag) { if (flag == 0) { Square source = Move_source(move); Square target = Move_target(move); Piece_T Piece = Piece_fromIndex(Move_piece(move)); + eColor color = CBoard_side(cboard); - CBoard_piece_move(self, Piece, source, target); - - if (Move_capture(move)) { - CBoard_colorBB_pop(self, !Piece_color(Piece), target); - ePiece i; - for (i = 0; i < 6; i++) { - if (i != Piece_piece(Piece) && CBoard_pieceBB_get(self, i, target)) { - CBoard_pieceBB_pop(self, i, target); - break; - } - } - } + if (!Move_capture(move)) + CBoard_piece_move(cboard, Piece, source, target); + else + CBoard_piece_capture(cboard, Piece, source, target); if (Move_promote(move)) { Piece_T Promote = Piece_fromIndex(Move_promote(move)); - CBoard_pieceBB_pop(self, Piece_piece(Piece), target); - CBoard_pieceBB_set(self, Piece_piece(Promote), target); + CBoard_piece_pop(cboard, Piece, target); + CBoard_piece_set(cboard, Promote, target); } - if (Move_enpassant(move)) { - if (Piece_color(Piece) == WHITE) - CBoard_piece_pop(self, Piece_get(PAWN, !Piece_color(Piece)), - target - 8); - else - CBoard_piece_pop(self, Piece_get(PAWN, !Piece_color(Piece)), - target + 8); - } + { + int ntarget = target + (color == WHITE ? -8 : +8); + if (Move_enpassant(move)) + CBoard_piece_pop(cboard, Piece_get(PAWN, !color), ntarget); - if (Move_double(move)) - CBoard_enpassant_set(self, - target + (Piece_color(Piece) == WHITE ? -8 : +8)); - else - CBoard_enpassant_set(self, no_sq); + CBoard_enpassant_set(cboard, Move_double(move) ? ntarget : no_sq); + } if (Move_castle(move)) { - 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); - CBoard_castle_pop(self, WK); - CBoard_castle_pop(self, WQ); - } else { - 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); - CBoard_castle_pop(self, BK); - CBoard_castle_pop(self, BQ); + Piece_T Rook = Piece_get(ROOK, CBoard_side(cboard)); + switch (target) { + case g1: CBoard_piece_move(cboard, Rook, h1, f1); break; + case c1: CBoard_piece_move(cboard, Rook, a1, d1); break; + case g8: CBoard_piece_move(cboard, Rook, h8, f8); break; + case c8: CBoard_piece_move(cboard, Rook, a8, d8); break; + default: break; } } - CBoard_castle_and(self, castling_rights[source]); - CBoard_castle_and(self, castling_rights[target]); + CBoard_castle_and(cboard, castling_rights[source]); + CBoard_castle_and(cboard, castling_rights[target]); - if (!CBoard_isCheck(self)) { - CBoard_side_switch(self); + if (!CBoard_isCheck(cboard)) { + CBoard_side_switch(cboard); return 1; } else return 0; } else { - if (Move_capture(move)) { - make_move(self, move, 0); - return 1; - } else + if (Move_capture(move)) + return make_move(cboard, move, 0); + else return 0; } - - return 0; } long nodes = 0; @@ -295,10 +273,8 @@ void perft_driver(CBoard_T self, int depth) { return; } + MoveList_T moves = generate_moves(self, &moveList[depth]); CBoard_T backup = CBoard_new(); - MoveList_T moves; - - moves = generate_moves(self, &moveList[depth]); for (int i = 0; i < moves->count; i++, CBoard_copy(backup, self)) { CBoard_copy(self, backup); @@ -311,14 +287,11 @@ void perft_driver(CBoard_T self, int depth) { } void perft_test(CBoard_T self, int depth) { - CBoard_T backup = CBoard_new(); + MoveList_T moves = generate_moves(self, &moveList[depth]); + CBoard_T backup = CBoard_new(); + long start = get_time_ms(); printf("\n Performance test\n\n"); - - MoveList_T moves; - moves = generate_moves(self, &moveList[depth]); - long start = get_time_ms(); - for (int i = 0; i < moves->count; i++, CBoard_copy(backup, self)) { CBoard_copy(self, backup); if (!make_move(self, moves->moves[i], 0)) @@ -330,9 +303,6 @@ void perft_test(CBoard_T self, int depth) { square_to_coordinates[Move_target(moves->moves[i])], old_nodes); } - moveList[depth].count = 0; - - // print results printf("\nNodes searched: %ld\n\n", nodes); return; printf("\n Depth: %d\n", depth); @@ -349,7 +319,7 @@ int main(void) { init_all(); CBoard_T board = CBoard_fromFEN(NULL, tricky_position); - perft_test(board, 4); + perft_test(board, 5); return 0; }