stellarUCI 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 16:19:08 +0200 |
Constexpr random and zobrist hashing init
Diffstat:M | src/board/CMakeLists.txt | | | - |
M | src/board/board.cpp | | | ++++---- |
D | src/board/zobrist.cpp | | | -------------------------------------------------------------------------------- |
M | src/engine/CMakeLists.txt | | | - |
M | src/engine/engine.cpp | | | ----- |
M | src/include/board.hpp | | | --- |
M | src/include/random.hpp | | | ++++++++++++++++++++++++++++++++++++++++--- |
M | src/include/zobrist.hpp | | | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ |
M | src/moves/moves_make.cpp | | | ++++---- |
M | src/perft/CMakeLists.txt | | | - |
M | src/perft/perft.cpp | | | +--- |
D | src/utils/CMakeLists.txt | | | ------- |
D | src/utils/random.cpp | | | ---------------------------- |
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);
}