stellarUCI 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 16:10:46 +0200 |
More Refactoring
Diffstat:M | include/CBoard.h | | | ++++++++++++++++++++++-------------------------- |
M | include/attack.h | | | -- |
M | include/utils.h | | | ++ |
M | src/CBoard.c | | | +++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------- |
M | src/engine.c | | | ++++++++++++++++++++++++++++++++-------------------------------------------------- |
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;
}