stellar

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

commit 3be4123c8c5cbdadfab02532d2bfcb9bdb173083
parent b9f9ac98b25274ffa436386189298cc72c885dc2
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date:   Fri, 11 Aug 2023 18:19:08 +0200

Constexpr random and zobrist hashing init

Diffstat:
Msrc/board/CMakeLists.txt | 1-
Msrc/board/board.cpp | 8++++----
Dsrc/board/zobrist.cpp | 80-------------------------------------------------------------------------------
Msrc/engine/CMakeLists.txt | 1-
Msrc/engine/engine.cpp | 5-----
Msrc/include/board.hpp | 3---
Msrc/include/random.hpp | 43++++++++++++++++++++++++++++++++++++++++---
Msrc/include/zobrist.hpp | 100++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Msrc/moves/moves_make.cpp | 8++++----
Msrc/perft/CMakeLists.txt | 1-
Msrc/perft/perft.cpp | 4+---
Dsrc/utils/CMakeLists.txt | 7-------
Dsrc/utils/random.cpp | 28----------------------------
13 files changed, 143 insertions(+), 146 deletions(-)

diff --git a/src/board/CMakeLists.txt b/src/board/CMakeLists.txt @@ -1,6 +1,5 @@ add_library(board OBJECT board.cpp - zobrist.cpp ) target_include_directories(board diff --git a/src/board/board.cpp b/src/board/board.cpp @@ -83,13 +83,13 @@ void Board::and_castle(uint8_t right) { void Board::switch_side(void) { side = (side == Color::BLACK) ? Color::WHITE : Color::BLACK; - hash ^= zobrist_key_side(); + hash ^= Zobrist::key_side(); } void Board::set_enpassant(Square target) { - if (enpassant != Square::no_sq) hash ^= zobrist_key_enpassant(enpassant); + if (enpassant != Square::no_sq) hash ^= Zobrist::key_enpassant(enpassant); - if (target != Square::no_sq) hash ^= zobrist_key_enpassant(target); + if (target != Square::no_sq) hash ^= Zobrist::key_enpassant(target); enpassant = target; } @@ -184,7 +184,7 @@ Board::Board(const std::string &fen) { } if (fen[++i] != '-') enpassant = square_from_coordinates(fen.data() + i); - hash = zobrist_hash(*this); + hash = Zobrist::hash(*this); } std::ostream &operator<<(std::ostream &os, const Board &board) { diff --git a/src/board/zobrist.cpp b/src/board/zobrist.cpp @@ -1,80 +0,0 @@ -#include "zobrist.hpp" -#include "piece.hpp" -#include "random.hpp" -#include "utils_cpp.hpp" - -U64 castle_keys[16]; -U64 enpassant_keys[64]; -U64 piece_keys[12][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[to_underlying(square)]; -} -U64 zobrist_key_piece(const piece::Piece &piece, Square square) { - return piece_keys[piece.index][to_underlying(square)]; -} - -void init_hash_keys() { - random_state_reset(); - - for (piece::Type type : piece::TypeIter()) { - int piece_index_white = piece::get(type, Color::WHITE).index; - int piece_index_black = piece::get(type, Color::BLACK).index; - for (int square = 0; square < 64; square++) { - piece_keys[piece_index_white][square] = random_get_U64(); - piece_keys[piece_index_black][square] = random_get_U64(); - } - } - - for (int square = 0; square < 64; square++) { - enpassant_keys[square] = random_get_U64(); - } - - for (int castle = 0; castle < 16; castle++) { - castle_keys[castle] = random_get_U64(); - } - - side_key = random_get_U64(); -} - -void zobrist_init(void) { - init_hash_keys(); -} - -U64 zobrist_hash(const Board &board) { - U64 key_final = C64(0); - uint8_t square; - - for (piece::Type type : piece::TypeIter()) { - const piece::Piece &piece_white = piece::get(type, Color::WHITE); - int piece_white_index = piece_white.index; - U64 bitboard_white = board.get_bitboard_piece(piece_white); - - bitboard_for_each_bit(square, bitboard_white) { - key_final ^= piece_keys[piece_white_index][square]; - } - - const piece::Piece &piece_black = piece::get(type, Color::BLACK); - int piece_black_index = piece_black.index; - U64 bitboard_black = board.get_bitboard_piece(piece_black); - - bitboard_for_each_bit(square, bitboard_black) { - key_final ^= piece_keys[piece_black_index][square]; - } - } - - key_final ^= castle_keys[board.get_castle()]; - - if (board.get_side() == Color::BLACK) key_final ^= side_key; - if (board.get_enpassant() != Square::no_sq) - key_final ^= enpassant_keys[to_underlying(board.get_enpassant())]; - - return key_final; -} diff --git a/src/engine/CMakeLists.txt b/src/engine/CMakeLists.txt @@ -7,7 +7,6 @@ add_executable(engine target_link_libraries(engine PRIVATE board PRIVATE moves - PRIVATE random ) target_link_libraries(engine PRIVATE "cul") diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp @@ -497,12 +497,7 @@ void uci_loop(void) { /* MAIN */ -void init(void) { - zobrist_init(); -} - int main(void) { - init(); uci_loop(); return 0; } diff --git a/src/include/board.hpp b/src/include/board.hpp @@ -40,7 +40,6 @@ class Board { U64 get_bitboard_piece_attacks(piece::Type piece, Color color, Square square) const; U64 get_bitboard_piece_attacks(const piece::Piece &piece, Square square) const; - // exception if not found Color get_square_piece_color(Square square) const; piece::Type get_square_piece_type(Square square) const; const piece::Piece *get_square_piece(Square square) const; @@ -76,6 +75,4 @@ class Board { uint8_t castle = 0; }; -const piece::Piece &board_square_piece(const Board *self, Square square, Color side); - #endif diff --git a/src/include/random.hpp b/src/include/random.hpp @@ -3,8 +3,45 @@ #include "utils_cpp.hpp" -void random_state_reset(); -U32 random_get_U32(); -U64 random_get_U64(); +class Random { + public: + constexpr Random(void) { + } + constexpr Random(U64 seed) : state(seed) { + } + + constexpr U64 operator()(void) { + return get_U64(); + } + + constexpr void reset(void) { + state = seed; + } + + constexpr U32 get_U32(void) { + U32 number = state; + + number ^= number << 13; + number ^= number >> 17; + number ^= number << 5; + + return state = number; + } + + constexpr U64 get_U64(void) { + U64 n1, n2, n3, n4; + + n1 = (U64)(get_U32()) & C64(0xFFFF); + n2 = (U64)(get_U32()) & C64(0xFFFF); + n3 = (U64)(get_U32()) & C64(0xFFFF); + n4 = (U64)(get_U32()) & C64(0xFFFF); + + return n1 | (n2 << 16) | (n3 << 32) | (n4 << 48); + } + + private: + static inline constexpr const U32 seed = C32(1804289383); + U32 state = seed; +}; #endif diff --git a/src/include/zobrist.hpp b/src/include/zobrist.hpp @@ -2,13 +2,101 @@ #define STELLAR_ZOBRIST_H #include "board.hpp" +#include "piece.hpp" +#include "random.hpp" -void zobrist_init(void); -U64 zobrist_hash(const Board &board); +#include <algorithm> +#include <array> +#include <random> -U64 zobrist_key_side(void); -U64 zobrist_key_castle(int exp); -U64 zobrist_key_enpassant(Square square); -U64 zobrist_key_piece(const piece::Piece &piece, Square square); +class Zobrist { + public: + Zobrist() = delete; + + static inline constexpr U64 key_side(void) { + return keys_side; + } + + static inline constexpr U64 key_castle(int exp) { + return keys_castle[exp]; + } + + static inline constexpr U64 key_enpassant(Square square) { + return keys_enpassant[to_underlying(square)]; + } + + static inline constexpr U64 key_piece(const piece::Piece &piece, Square square) { + return keys_piece[piece.index][to_underlying(square)]; + } + + static inline U64 hash(const Board &board) { + U64 key_final = C64(0); + uint8_t square; + + for (piece::Type type : piece::TypeIter()) { + const piece::Piece &piece_white = piece::get(type, Color::WHITE); + int piece_white_index = piece_white.index; + U64 bitboard_white = board.get_bitboard_piece(piece_white); + + bitboard_for_each_bit(square, bitboard_white) { + key_final ^= keys_piece[piece_white_index][square]; + } + + const piece::Piece &piece_black = piece::get(type, Color::BLACK); + int piece_black_index = piece_black.index; + U64 bitboard_black = board.get_bitboard_piece(piece_black); + + bitboard_for_each_bit(square, bitboard_black) { + key_final ^= keys_piece[piece_black_index][square]; + } + } + + key_final ^= keys_castle[board.get_castle()]; + + if (board.get_side() == Color::BLACK) key_final ^= keys_side; + if (board.get_enpassant() != Square::no_sq) + key_final ^= keys_enpassant[to_underlying(board.get_enpassant())]; + + return key_final; + } + + private: + typedef std::array<std::array<U64, 64>, 12> key_piece_array; + static inline constexpr const key_piece_array keys_piece = []() constexpr -> key_piece_array { + key_piece_array key_piece; + Random gen(C64(1804289383)); + for (piece::Type type : piece::TypeIter()) { + int piece_index_white = piece::get(type, Color::WHITE).index; + int piece_index_black = piece::get(type, Color::BLACK).index; + for (int square = 0; square < 64; square++) { + key_piece[piece_index_white][square] = gen(); + key_piece[piece_index_black][square] = gen(); + } + } + return key_piece; + }(); + + typedef std::array<U64, 64> key_enpassant_array; + static inline constexpr const key_enpassant_array keys_enpassant = []() constexpr -> key_enpassant_array { + key_enpassant_array key_enpassant; + Random gen(C32(337245213)); + for (int castle = 0; castle < 64; castle++) { + key_enpassant[castle] = gen(); + } + return key_enpassant; + }(); + + typedef std::array<U64, 16> key_castle_array; + static inline constexpr const key_castle_array keys_castle = []() constexpr -> key_castle_array { + key_castle_array key_castle; + Random gen(C32(3642040919)); + for (int castle = 0; castle < 16; castle++) { + key_castle[castle] = gen(); + } + return key_castle; + }(); + + static inline constexpr const U64 keys_side = Random(C32(1699391443))(); +}; #endif diff --git a/src/moves/moves_make.cpp b/src/moves/moves_make.cpp @@ -17,12 +17,12 @@ const int castling_rights[64] = { void _piece_remove(Board &board, const piece::Piece &piece, Square square) { board.pop_piece(piece, square); - board.xor_hash(zobrist_key_piece(piece, square)); + board.xor_hash(Zobrist::key_piece(piece, square)); } void _piece_set(Board &board, const piece::Piece &piece, Square square) { board.set_piece(piece, square); - board.xor_hash(zobrist_key_piece(piece, square)); + board.xor_hash(Zobrist::key_piece(piece, square)); } void _piece_move(Board &board, const piece::Piece &piece, Square source, Square target) { @@ -74,10 +74,10 @@ int move_make(Move move, Board &board, int flag) { if (target == Square::c8) _piece_move(board, rook_black, Square::a8, Square::d8); } - board.xor_hash(zobrist_key_castle(board.get_castle())); + board.xor_hash(Zobrist::key_castle(board.get_castle())); board.and_castle(castling_rights[move_source(move)]); board.and_castle(castling_rights[move_target(move)]); - board.xor_hash(zobrist_key_castle(board.get_castle())); + board.xor_hash(Zobrist::key_castle(board.get_castle())); if (!board.is_check()) { board.switch_side(); diff --git a/src/perft/CMakeLists.txt b/src/perft/CMakeLists.txt @@ -8,7 +8,6 @@ endif() target_link_libraries(perft PRIVATE board PRIVATE moves - PRIVATE random ) target_link_libraries(perft PRIVATE "cul") diff --git a/src/perft/perft.cpp b/src/perft/perft.cpp @@ -1,3 +1,4 @@ +#include <iomanip> #include <pthread.h> #include <stdbool.h> #include <stdio.h> @@ -99,7 +100,6 @@ void *perft_thread(void *arg) { copy = board; if (!move_make(move, copy, 0)) continue; - // std::cout << copy << std::endl; if (shared->depth != 1) { perft_driver(copy, shared->depth - 1, &result); @@ -158,8 +158,6 @@ int main(int argc, char *argv[]) { } } - zobrist_init(); - PerftResult res = perft_test(fen, depth, thread_num); perft_result_print(res); } diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt @@ -1,7 +0,0 @@ -add_library(random OBJECT - random.cpp -) - -target_include_directories(random - PUBLIC "${PROJECT_SOURCE_DIR}/src/include" -) diff --git a/src/utils/random.cpp b/src/utils/random.cpp @@ -1,28 +0,0 @@ -#include "random.hpp" - -U32 state = C32(1804289383); - -void random_state_reset() { - state = C32(1804289383); -} - -U32 random_get_U32() { - U32 number = state; - - number ^= number << 13; - number ^= number >> 17; - number ^= number << 5; - - return state = number; -} - -U64 random_get_U64() { - U64 n1, n2, n3, n4; - - n1 = (U64)(random_get_U32()) & C64(0xFFFF); - n2 = (U64)(random_get_U32()) & C64(0xFFFF); - n3 = (U64)(random_get_U32()) & C64(0xFFFF); - n4 = (U64)(random_get_U32()) & C64(0xFFFF); - - return n1 | (n2 << 16) | (n3 << 32) | (n4 << 48); -}