stellar

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

commiteb0c42bd2bf2f52666067bf7f1fad41dfe4948a9
parent050c1a0016042f5f82214a5311a2ddc1e2dc30bd
authorDimitrije Dobrota <mail@dimitrijedobrota.com>
dateMon, 3 Oct 2022 10:34:26 +0200

Move rewrite

Diffstat:
Minclude/CBoard.h|+--
Msrc/CBoard.c|++++++++++-----------
Msrc/engine.c|+++++++++++++++++++++++++++++++++++++++++++++++++---------------------------------

3 files changed, 81 insertions(+), 59 deletions(-)


diff --git a/include/CBoard.h b/include/CBoard.h

@@ -37,8 +37,7 @@ 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_capture(CBoard_T self, Piece_T Piece, Piece_T Taken, 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);

diff --git a/src/CBoard.c b/src/CBoard.c

@@ -32,12 +32,12 @@ struct Piece_T Pieces[2][6] = {

[KING] = {.color = WHITE, .code = 'K', .asci = 'K', .unicode = "♔ ", .piece = KING, .attacks = get_king_attacks},
},
{
[PAWN] = {.color = BLACK, .code = 'p', .asci = 'p', .unicode = "♟ ", .piece = PAWN, .attacks = get_bpawn_attacks},
[KNIGHT] = {.color = BLACK, .code = 'n', .asci = 'n', .unicode = "♞ ", .piece = KNIGHT, .attacks = get_knight_attacks},
[BISHOP] = {.color = BLACK, .code = 'b', .asci = 'b', .unicode = "♝ ", .piece = BISHOP, .attacks = get_bishop_attacks},
[ROOK] = {.color = BLACK, .code = 'r', .asci = 'r', .unicode = "♜ ", .piece = ROOK, .attacks = get_rook_attacks},
[QUEEN] = {.color = BLACK, .code = 'q', .asci = 'q', .unicode = "♛ ", .piece = QUEEN, .attacks = get_queen_attacks},
[KING] = {.color = BLACK, .code = 'k', .asci = 'k', .unicode = "♚ ", .piece = KING, .attacks = get_king_attacks},
[PAWN] = {.color = BLACK, .code = 'p', .asci = 'p', .unicode = "♟ ", .piece = PAWN, .attacks = get_bpawn_attacks},
[KNIGHT] = {.color = BLACK, .code = 'n', .asci = 'n', .unicode = "♞ ", .piece = KNIGHT, .attacks = get_knight_attacks},
[BISHOP] = {.color = BLACK, .code = 'b', .asci = 'b', .unicode = "♝ ", .piece = BISHOP, .attacks = get_bishop_attacks},
[ROOK] = {.color = BLACK, .code = 'r', .asci = 'r', .unicode = "♜ ", .piece = ROOK, .attacks = get_rook_attacks},
[QUEEN] = {.color = BLACK, .code = 'q', .asci = 'q', .unicode = "♛ ", .piece = QUEEN, .attacks = get_queen_attacks},
[KING] = {.color = BLACK, .code = 'k', .asci = 'k', .unicode = "♚ ", .piece = KING, .attacks = get_king_attacks},
},
};
// clang-format on

@@ -142,12 +142,11 @@ 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;
void CBoard_piece_capture(CBoard_T self, Piece_T Piece, Piece_T Taken,
Square source, Square target) {
CBoard_piece_pop(self, Piece, source);
if ((taken = CBoard_square_piece(self, target, !self->side)))
CBoard_piece_pop(self, taken, target);
if (Taken)
CBoard_piece_pop(self, Taken, target);
CBoard_piece_set(self, Piece, target);
}

diff --git a/src/engine.c b/src/engine.c

@@ -25,29 +25,38 @@

typedef U32 Move;
Move Move_encode(Square src, Square tgt, Piece_T Piece, Piece_T Promotion,
int capture, int dbl, int enpassant, int castle) {
assert(Piece);
int prom = (Promotion == 0) ? 0 : Piece_index(Promotion);
return (src) | (tgt << 6) | (Piece_index(Piece) << 12) | (prom << 16) |
(capture << 20) | (dbl << 21) | (enpassant << 22) | (castle << 23);
}
Move Move_encode(Square src, Square tgt, Piece_T Piece, Piece_T Capture,
Piece_T Promote, int dbl, int enpassant, int castle) {
Move move = C32(0);
move |= (src) | (tgt << 6) | (dbl << 27) | (enpassant << 28) | (castle << 29);
move |= (Piece_index(Piece) << 12);
if (Capture != NULL) {
move |= (Piece_index(Capture) << 17);
move |= (1 << 30);
}
#define Move_source(move) (((move)&C32(0x00003f)))
#define Move_target(move) (((move)&C32(0x000fc0)) >> 6)
#define Move_piece(move) Piece_fromIndex((((move)&C32(0x00f000)) >> 12))
#define Move_capture(move) (((move)&C32(0x100000)) >> 20)
#define Move_double(move) (((move)&C32(0x200000)) >> 21)
#define Move_enpassant(move) (((move)&C32(0x400000)) >> 22)
#define Move_castle(move) (((move)&C32(0x800000)) >> 23)
Piece_T Move_promote(Move move) {
int index = (move & C32(0x0f0000)) >> 16;
if (!index)
return NULL;
return Piece_fromIndex(index);
if (Promote != NULL) {
move |= (Piece_index(Promote) << 22);
move |= (1 << 31);
}
return move;
}
#define Move_source(move) (((move)&C32(0x0000003f)))
#define Move_target(move) (((move)&C32(0x00000fc0)) >> 6)
#define Move_double(move) (((move)&C32(0x08000000)) >> 27)
#define Move_enpassant(move) (((move)&C32(0x10000000)) >> 28)
#define Move_castle(move) (((move)&C32(0x20000000)) >> 29)
#define Move_capture(move) (((move)&C32(0x40000000)) >> 30)
#define Move_promote(move) (((move)&C32(0x80000000)) >> 31)
#define Move_piece(move) (Piece_fromIndex(((move)&C32(0x0001F000)) >> 12))
#define Move_piece_capture(move) \
(assert(Move_capture(move)), Piece_fromIndex(((move)&C32(0x003E0000)) >> 17))
#define Move_piece_promote(move) \
(assert(Move_promote(move)), Piece_fromIndex(((move)&C32(0x07C00000)) >> 22))
// clang-format off
const int castling_rights[64] = {
13, 15, 15, 15, 12, 15, 15, 14,

@@ -196,10 +205,10 @@ Stats_T Stats_new(void) {

void Stats_free(Stats_T *p) { FREE(*p); }
int Move_score(Stats_T stats, CBoard_T board, Move move) {
int Move_score(Stats_T stats, Move move) {
if (Move_capture(move)) {
return Score_capture(CBoard_piece_get(board, Move_source(move)),
CBoard_piece_get(board, Move_target(move)));
return Score_capture(Piece_piece(Move_piece(move)),
Piece_piece(Move_piece_capture(move)));
} else {
if (stats->killer_moves[0][stats->ply] == move)
return 9000;

@@ -214,13 +223,15 @@ int Move_score(Stats_T stats, CBoard_T board, Move move) {

}
void Move_print(Move move) {
printf("%5s %5s %5s %5c %4d %4d %4d %4d\n",
printf("%5s %5s %2s %2s %2s %4d %4d %4d %4d %4d\n",
square_to_coordinates[Move_source(move)],
square_to_coordinates[Move_target(move)],
Piece_unicode(Move_piece(move)),
Move_promote(move) ? Piece_asci(Move_promote(move)) : 'X',
Move_capture(move) ? 1 : 0, Move_double(move) ? 1 : 0,
Move_enpassant(move) ? 1 : 0, Move_castle(move) ? 1 : 0);
Move_capture(move) ? Piece_unicode(Move_piece_capture(move)) : "X ",
Move_promote(move) ? Piece_unicode(Move_piece_promote(move)) : "X ",
Move_double(move) ? 1 : 0, Move_enpassant(move) ? 1 : 0,
Move_castle(move) ? 1 : 0, Move_capture(move) ? 1 : 0,
Move_promote(move) ? 1 : 0);
}
typedef struct MoveList_T *MoveList_T;

@@ -246,16 +257,16 @@ void MoveList_add(MoveList_T self, Move move) {

}
void MoveList_print(MoveList_T self) {
printf(" From To Pi Prmt Cap Dbl Enp Cst\n");
printf(" From To Pi Cap Prmt Dbl Enp Cst C P\n");
for (int i = 0; i < self->count; i++)
Move_print(self->moves[i]);
printf("Total: %d\n", self->count);
}
void MoveList_sort(Stats_T stats, CBoard_T board, MoveList_T list) {
void MoveList_sort(Stats_T stats, MoveList_T list) {
int score[list->count];
for (int i = 0; i < list->count; i++)
score[i] = Move_score(stats, board, list->moves[i]);
score[i] = Move_score(stats, list->moves[i]);
for (int i = 0; i < list->count; i++)
for (int j = i + 1; j < list->count; j++)

@@ -278,9 +289,9 @@ void MoveList_sort(Stats_T stats, CBoard_T board, MoveList_T list) {

((color == BLACK && source >= a7 && source <= h7) || \
(color == WHITE && source >= a2 && source <= h2))
#define pawn_promote(source, target, index, capture) \
#define pawn_promote(source, target, Piece, Capture) \
for (int i = 1; i < 5; i++) { \
move = Move_encode(source, target, index, Piece_get(i, color), capture, 0, \
move = Move_encode(source, target, Piece, Capture, Piece_get(i, color), 0, \
0, 0); \
MoveList_add(moves, move); \
}

@@ -318,9 +329,13 @@ MoveList_T MoveList_generate(MoveList_T moves, CBoard_T board) {

CBoard_colorBB(board, !color);
bitboard_for_each_bit(tgt, attack) {
if (pawn_canPromote(color, src)) {
pawn_promote(src, tgt, Piece, 1);
pawn_promote(src, tgt, Piece,
CBoard_square_piece(board, tgt, !color));
} else {
MoveList_add(moves, Move_encode(src, tgt, Piece, 0, 1, 0, 0, 0));
MoveList_add(moves,
Move_encode(src, tgt, Piece,
CBoard_square_piece(board, tgt, !color), 0,
0, 0, 0));
}
}
}

@@ -329,8 +344,10 @@ MoveList_T MoveList_generate(MoveList_T moves, CBoard_T board) {

if (CBoard_enpassant(board) != no_sq &&
CBoard_piece_attacks(board, Piece, src) &
(C64(1) << CBoard_enpassant(board)))
MoveList_add(moves, Move_encode(src, CBoard_enpassant(board), Piece,
0, 1, 0, 1, 0));
MoveList_add(moves,
Move_encode(src, CBoard_enpassant(board), Piece,
CBoard_square_piece(board, tgt, !color), 0,
0, 1, 0));
}
}
}

@@ -343,8 +360,10 @@ MoveList_T MoveList_generate(MoveList_T moves, CBoard_T board) {

U64 attack = CBoard_piece_attacks(board, Piece, src) &
~CBoard_colorBB(board, color);
bitboard_for_each_bit(tgt, attack) {
int take = bit_get(CBoard_colorBB(board, !color), tgt);
MoveList_add(moves, Move_encode(src, tgt, Piece, 0, take, 0, 0, 0));
/* int take = bit_get(CBoard_colorBB(board, !color), tgt); */
MoveList_add(moves, Move_encode(src, tgt, Piece,
CBoard_square_piece(board, tgt, !color),
0, 0, 0, 0));
}
}
}

@@ -402,11 +421,12 @@ int Move_make(Move move, CBoard_T board, int flag) {

if (!Move_capture(move))
CBoard_piece_move(board, Piece, source, target);
else
CBoard_piece_capture(board, Piece, source, target);
CBoard_piece_capture(board, Piece, Move_piece_capture(move), source,
target);
if (Move_promote(move)) {
CBoard_piece_pop(board, Piece, target);
CBoard_piece_set(board, Move_promote(move), target);
CBoard_piece_set(board, Move_piece_promote(move), target);
}
{

@@ -485,7 +505,7 @@ int quiescence(Stats_T stats, CBoard_T board, int alpha, int beta) {

copy = CBoard_new();
moves = MoveList_generate(NULL, board);
MoveList_sort(stats, board, moves);
MoveList_sort(stats, moves);
for (int i = 0; i < MoveList_size(moves); i++) {
CBoard_copy(board, copy);

@@ -537,7 +557,7 @@ int negamax(Stats_T stats, CBoard_T board, int alpha, int beta, int depth) {

depth++;
int legal_moves = 0;
MoveList_sort(stats, board, list);
MoveList_sort(stats, list);
for (int i = 0; i < MoveList_size(list); i++) {
Move move = MoveList_move(list, i);

@@ -593,7 +613,7 @@ void Move_print_UCI(Move move) {

printf("%s%s", square_to_coordinates[Move_source(move)],
square_to_coordinates[Move_target(move)]);
if (Move_promote(move))
printf(" %c", Piece_asci(Move_promote(move)));
printf(" %c", Piece_asci(Move_piece_promote(move)));
}
void search_position(CBoard_T board, int depth) {

@@ -694,7 +714,7 @@ Move parse_move(CBoard_T board, char *move_string) {

Move move = moves->moves[i];
if (Move_source(move) == source && Move_target(move) == target) {
if (move_string[4]) {
if (tolower(Piece_code(Move_promote(move))) != move_string[4])
if (tolower(Piece_code(Move_piece_promote(move))) != move_string[4])
continue;
}
result = move;

@@ -822,6 +842,7 @@ void perft_driver(CBoard_T board, int depth) {

perft_driver(copy, depth - 1);
}
MoveList_reset(list);
CBoard_free(&copy);
}
void perft_test(CBoard_T board, int depth) {

@@ -844,6 +865,7 @@ void perft_test(CBoard_T board, int depth) {

square_to_coordinates[Move_target(move)], old_nodes);
}
MoveList_reset(list);
CBoard_free(&copy);
printf("\nNodes searched: %ld\n\n", nodes);
return;

@@ -863,7 +885,6 @@ int main(void) {

init_all();
int debug = 1;
if (debug) {
printf("debugging!\n");
CBoard_T board = NULL;
MoveList_T list = NULL;
Instruction_T inst = NULL;

@@ -872,7 +893,10 @@ int main(void) {

board = CBoard_fromFEN(board, tricky_position);
CBoard_print(board);
search_position(board, 5);
/* MoveList_print(MoveList_generate(NULL, board)); */
perft_test(board, 5);
/* search_position(board, 5); */
CBoard_free(&board);
} else
uci_loop();
return 0;