stellar

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 17:20:48 +0200

Fix move generating and incremental hashing

Diffstat:
Msrc/board/board.c | 50+++++++++++++++++++-------------------------------
Msrc/board/zobrist.c | 7+++++++
Msrc/include/board.h | 9++-------
Msrc/include/zobrist.h | 5+++++
Msrc/moves/moves.c | 87++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Msrc/perft/CMakeLists.txt | 1+
Msrc/perft/perft.c | 4++++
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); }