stellar

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

commit 55197a63e49580de502e4ec9885ea85a10ef5049
parent 3ca8bda95f268b5177b3a0c22bf7bbcd21df775c
author Dimitrije Dobrota <mail@dimitrijedobrota.com>
date Mon, 7 Aug 2023 15:20:48 +0200

Fix move generating and incremental hashing

Diffstat:
M src/board/board.c | +++++++++++++++++++ -------------------------------
M src/board/zobrist.c | +++++++
M src/include/board.h | ++ -------
M src/include/zobrist.h | +++++
M src/moves/moves.c | ++++++++++++++++++++++++++++++++++++++++++++++++++++ ------------------------------
M src/perft/CMakeLists.txt | +
M src/perft/perft.c | ++++

7 files changed, 93 insertions(+), 70 deletions(-)


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

@@ -6,6 +6,7 @@ #include <cul/mem.h> #include "board.h"
#include "utils.h"
#include "zobrist.h" Board *board_new(void) {

@@ -29,18 +30,10 @@ U64 board_occupancy(const Board *self) { return self->color[WHITE] | self->color[BLACK]; }
U64 board_piece_get_internal(const Board *self, ePiece piece, Square target) {
return bit_get(self->piece[piece], target);
}
U64 board_pieceSet(const Board *self, Piece piece) { return self->piece[piece_piece(piece)] & self->color[piece_color(piece)]; }
void board_enpassant_set(Board *self, Square target) {
self->enpassant = target;
}
void board_color_pop(Board *self, eColor color, Square target) { bit_pop(self->color[color], target); }

@@ -69,29 +62,10 @@ void board_piece_set(Board *self, Piece piece, Square square) { bit_set(self->color[piece_color(piece)], square); }
void board_piece_move(Board *self, Piece Piece, Square source, Square target) {
board_piece_pop(self, Piece, source);
board_piece_set(self, Piece, target);
}
U64 board_piece_attacks(const Board *self, Piece piece, Square src) { return piece_attacks(piece)(src, board_occupancy(self)); }
void board_piece_capture(Board *self, Piece piece, Piece taken, Square source,
Square target) {
board_piece_pop(self, piece, source);
if (taken) board_piece_pop(self, taken, target);
board_piece_set(self, piece, target);
}
void board_castle_pop(Board *self, eCastle castle) {
bit_pop(self->castle, bit_lsb_index(castle));
}
void board_castle_and(Board *self, int exp) { self->castle &= exp; }
void board_side_switch(Board *self) { self->side = !self->side; }
int board_isCheck(const Board *self) { U64 king = self->piece[KING] & self->color[self->side]; return board_square_isAttack(self, bit_lsb_index(king), !self->side);

@@ -103,7 +77,7 @@ int board_square_isOccupied(const Board *self, Square square) { int board_square_isAttack(const Board *self, Square square, eColor side) { U64 occupancy = self->color[WHITE] | self->color[BLACK];
for (int i = 0; i < 6; i++) {
for (int i = KING; i >= PAWN; i--) {
if (piece_attacks(piece_get(i, !side))(square, occupancy) & self->piece[i] & self->color[side]) return 1;

@@ -112,10 +86,24 @@ int board_square_isAttack(const Board *self, Square square, eColor side) { return 0; }
void board_side_switch(Board *self) {
self->side = !self->side;
self->hash ^= zobrist_key_side();
}
void board_enpassant_set(Board *self, Square target) {
if (self->enpassant != no_sq)
self->hash ^= zobrist_key_enpassant(self->enpassant);
if (target != no_sq) self->hash ^= zobrist_key_enpassant(target);
self->enpassant = target;
}
void board_castle_and(Board *self, int exp) { self->castle &= exp; }
Piece board_square_piece(const Board *self, Square square, eColor color) { for (ePiece i = 0; i < 6; i++)
if (board_piece_get_internal(self, i, square))
return piece_get(i, color);
if (bit_get(self->piece[i], square)) return piece_get(i, color);
return NULL; }

@@ -217,6 +205,6 @@ void board_print(const Board *self) { printf(" Castling: %c%c%c%c\n", (self->castle & WK) ? 'K' : '-', (self->castle & WQ) ? 'Q' : '-', (self->castle & BK) ? 'k' : '-', (self->castle & BQ) ? 'q' : '-');
printf(" Hash: %llu\n", self->hash);
printf(" Hash: %llx\n", self->hash);
printf("\n"); }

diff --git a/ src/board/zobrist.c b/ src/board/zobrist.c

@@ -9,6 +9,13 @@ U64 enpassant_keys[64]; U64 piece_keys[16][64]; U64 side_key;
U64 zobrist_key_side(void) { return side_key; }
U64 zobrist_key_castle(int exp) { return castle_keys[exp]; }
U64 zobrist_key_enpassant(Square square) { return enpassant_keys[square]; }
U64 zobrist_key_piece(Piece piece, Square square) {
return piece_keys[piece_index(piece)][square];
}
void init_hash_keys() { random_state_reset();

diff --git a/ src/include/board.h b/ src/include/board.h

@@ -33,14 +33,13 @@ eColor board_side(const Board *self); Square board_enpassant(const Board *self); U64 board_hash(const Board *self);
void board_side_switch(Board *self);
void board_enpassant_set(Board *self, Square target);
void board_castle_and(Board *self, int exp);
U64 board_pieceSet(const Board *self, Piece piece); U64 board_piece_attacks(const Board *self, Piece piece, Square src);
void board_piece_capture(Board *self, Piece piece, Piece taken, Square source,
Square target);
void board_piece_move(Board *self, Piece Piece, Square square, Square target);
void board_piece_pop(Board *self, Piece Piece, Square square); void board_piece_set(Board *self, Piece Piece, Square square); int board_piece_get(const Board *self, Square square);

@@ -49,9 +48,6 @@ U64 board_color_get(const Board *self, eColor color, Square target); void board_color_pop(Board *self, eColor color, Square target); void board_color_set(Board *self, eColor color, Square target);
void board_castle_and(Board *self, int exp);
void board_castle_pop(Board *self, eCastle castle);
Piece board_square_piece(const Board *self, Square square, eColor side); int board_square_isAttack(const Board *self, Square square, eColor side); int board_square_isOccupied(const Board *self, Square square);

@@ -59,6 +55,5 @@ int board_square_isOccupied(const Board *self, Square square); Board *board_from_FEN(Board *board, const char *fen); int board_isCheck(const Board *self); void board_print(const Board *self);
void board_side_switch(Board *self);
#endif

diff --git a/ src/include/zobrist.h b/ src/include/zobrist.h

@@ -6,4 +6,9 @@ void zobrist_init(void); U64 zobrist_hash(const Board *board);
U64 zobrist_key_side(void);
U64 zobrist_key_castle(int exp);
U64 zobrist_key_enpassant(Square square);
U64 zobrist_key_piece(Piece piece, Square square);
#endif

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

@@ -4,7 +4,9 @@ #include <cul/assert.h> #include <cul/mem.h>
#include "board.h"
#include "moves.h"
#include "zobrist.h"
int move_cmp(Move a, Move b) { return *(uint32_t *)&a == *(uint32_t *)&b; }

@@ -128,10 +130,9 @@ MoveList *move_list_generate(MoveList *moves, const Board *board) { if (board_enpassant(board) != no_sq && board_piece_attacks(board, piece, src) & (C64(1) << board_enpassant(board)))
move_list_add(
moves, move_encode(src, board_enpassant(board), piece,
board_square_piece(board, tgt, !color),
0, 0, 1, 0));
move_list_add(moves,
move_encode(src, board_enpassant(board), piece,
piece_get(PAWN, !color), 0, 0, 1, 0));
} }

@@ -204,63 +205,85 @@ const int castling_rights[64] = { }; // clang-format on
int move_make(Move move, Board *board, int flag) {
if (flag == 0) {
void _piece_remove(Board *self, Piece piece, Square square) {
board_piece_pop(self, piece, square);
self->hash ^= zobrist_key_piece(piece, square);
}
Square source = move_source(move);
Square target = move_target(move);
void _piece_set(Board *self, Piece piece, Square square) {
board_piece_set(self, piece, square);
self->hash ^= zobrist_key_piece(piece, square);
}
void _piece_move(Board *self, Piece piece, Square source, Square target) {
_piece_remove(self, piece, source);
_piece_set(self, piece, target);
}
int move_make(Move move, Board *board, int flag) {
if (flag) {
if (move_capture(move)) return move_make(move, board, 0);
return 0;
} else {
Piece piece = move_piece(move); eColor color = board_side(board);
Square source = move_source(move);
Square target = move_target(move);
Square ntarget = target + (color == WHITE ? -8 : +8);
if (!move_capture(move))
board_piece_move(board, piece, source, target);
else
board_piece_capture(board, piece, move_piece_capture(move), source,
target);
if (move_promote(move)) {
board_piece_pop(board, piece, target);
board_piece_set(board, move_piece_promote(move), target);
if (!move_capture(move)) {
if (move_promote(move)) {
_piece_remove(board, piece, source);
_piece_set(board, move_piece_promote(move), target);
} else {
_piece_move(board, piece, source, target);
}
} else {
if (move_enpassant(move)) {
_piece_move(board, piece, source, target);
_piece_remove(board, move_piece_capture(move), ntarget);
} else if (move_promote(move)) {
_piece_remove(board, piece, source);
_piece_remove(board, move_piece_capture(move), target);
_piece_set(board, move_piece_promote(move), target);
} else {
_piece_remove(board, piece, source);
_piece_remove(board, move_piece_capture(move), target);
_piece_set(board, piece, target);
}
}
int ntarget = target + (color == WHITE ? -8 : +8);
if (move_enpassant(move))
board_piece_pop(board, piece_get(PAWN, !color), ntarget);
board_enpassant_set(board, move_double(move) ? ntarget : no_sq); if (move_castle(move)) { Piece Rook = piece_get(ROOK, board_side(board)); switch (target) { case g1:
board_piece_move(board, Rook, h1, f1);
_piece_move(board, Rook, h1, f1);
break; case c1:
board_piece_move(board, Rook, a1, d1);
_piece_move(board, Rook, a1, d1);
break; case g8:
board_piece_move(board, Rook, h8, f8);
_piece_move(board, Rook, h8, f8);
break; case c8:
board_piece_move(board, Rook, a8, d8);
_piece_move(board, Rook, a8, d8);
break; default: break; } }
board->hash ^= zobrist_key_castle(board_castle(board));
board_castle_and(board, castling_rights[source]); board_castle_and(board, castling_rights[target]);
board->hash ^= zobrist_key_castle(board_castle(board));
if (!board_isCheck(board)) { board_side_switch(board); return 1;
} else
return 0;
} else {
if (move_capture(move))
return move_make(move, board, 0);
else
return 0;
}
return 0;
} }

diff --git a/ src/perft/CMakeLists.txt b/ src/perft/CMakeLists.txt

@@ -19,6 +19,7 @@ target_link_libraries(perft PRIVATE piece PRIVATE score PRIVATE utils
PRIVATE random
) target_link_libraries(perft PRIVATE "cul")

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

@@ -11,6 +11,7 @@ #include "moves.h" #include "perft.h" #include "utils.h"
#include "zobrist.h"
// FEN debug positions #define tricky_position \

@@ -174,6 +175,9 @@ int main(int argc, char *argv[]) { } attacks_init();
zobrist_init();
board_print(board_from_FEN(NULL, fen));
PerftResult res = perft_test(fen, depth, thread_num); perft_result_print(res); }