stellar

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

commit 644090d7e796c3e13c7595700830ddcad8836754
parent 0218a1559240963bdc53c7157b1cb16cfa4878f0
author Dimitrije Dobrota < mail@dimitrijedobrota.com >
date Wed, 20 Mar 2024 18:51:51 +0000

Improve transposition table, add stats info

Diffstat:
M CMakeLists.txt | + -
M src/engine/CMakeLists.txt | ++++
M src/engine/engine.cpp | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ------
M src/perft/perft.cpp | +

4 files changed, 74 insertions(+), 7 deletions(-)


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

@@ -3,7 +3,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)


project(
Stellar
VERSION 1.3.8
VERSION 1.3.9
DESCRIPTION "Chess engine written in C++"
HOMEPAGE_URL https://git.dimitrijedobrota.com/stellar.git
LANGUAGES CXX

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

@@ -4,6 +4,10 @@ add_executable(engine

uci.cpp
)

option(STELLAR_STATS "Provide stats for analysis" OFF)
if(STELLAR_STATS)
add_definitions(-DUSE_STATS)
endif()

target_link_libraries(engine
PRIVATE Stellar_version

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

@@ -45,10 +45,44 @@ template <U64 size> class TTable_internal {

public:
static inline constexpr const int16_t unknown = 32500;

static void clear() { memset(table.data(), 0x00, size * sizeof(Hashe)); };
static void clear() {
memset(table.data(), 0x00, size * sizeof(Hashe));
#ifdef USE_STATS
accessed = 0, rewrite = 0, miss = 0;
#endif
};

#ifdef USE_STATS
static void print() {
std::cout << "Transposition table: " << std::endl;
std::cout << "\tSize: " << size << " entries (" << sizeof(Hashe) << "B per entry)" << std::endl;
std::cout << "\tSize: " << std::fixed << std::setprecision(2)
<< (double)size * sizeof(Hashe) / (1 << 20) << "MB" << std::endl;
std::cout << "\tReads: " << accessed << std::endl;
std::cout << "\tMisses: " << miss << "(" << (double)miss / accessed << "%)" << std::endl;
std::cout << "\tRewrite: " << rewrite << std::endl;
std::cout << "\tUsed " << (double)used() / size << "%" << std::endl;
}

static U64 used() {
U64 res = 0;

for (int i = 0; i < size; i++) {
if (table[i].key) res++;
}

return res;
}
#endif

static int16_t read(const Board &board, int ply, Move *best, int16_t alpha, int16_t beta, uint8_t depth) {
U64 hash = board.get_hash();
const Hashe &phashe = table[hash % table.size()];
const Hashe &phashe = table[hash % size];

#ifdef USE_STATS
accessed++;
#endif

if (phashe.key == hash) {
if (phashe.depth >= depth) {
int16_t score = phashe.score;

@@ -62,26 +96,54 @@ template <U64 size> class TTable_internal {

}
*best = phashe.best;
}
#ifdef USE_STATS
else {
miss++;
}
#endif
return unknown;
}

static void write(const Board &board, int ply, Move best, int16_t score, uint8_t depth,
Hashe::Flag flag) {
U64 hash = board.get_hash();
Hashe &phashe = table[hash % table.size()];
Hashe &phashe = table[hash % size];

if (score < -MATE_SCORE) score += ply;
if (score > MATE_SCORE) score -= ply;

if (phashe.key == hash) {
if (phashe.depth > depth) return;
}
#ifdef USE_STATS
else {
rewrite++;
}
#endif

phashe = {hash, best, depth, score, flag};
}

private:
static std::array<Hashe, size> table;

#ifdef USE_STATS
static U64 accessed, rewrite, miss;
#endif
};

template <U64 size> std::array<Hashe, size> TTable_internal<size>::table;

#ifdef USE_STATS
template <U64 size> U64 TTable_internal<size>::accessed = 0;
template <U64 size> U64 TTable_internal<size>::rewrite = 0;
template <U64 size> U64 TTable_internal<size>::miss = 0;
#endif

using TTable = TTable_internal<C64(0x2000023)>;

TTable ttable;

class PVTable {
public:
Move best(uint8_t ply = 0) { return table[0][ply]; }

@@ -107,9 +169,6 @@ std::ostream &operator<<(std::ostream &os, const PVTable &pvtable) {

return os;
}

using TTable = TTable_internal<C64(0x2FB4377)>;
TTable ttable;

static const uci::Settings *settings = nullptr;
static Board board;
static repetition::Table rtable;

@@ -476,5 +535,8 @@ int main() {

attack::init();
zobrist::init();
uci::loop();
#ifdef USE_STATS
engine::ttable.print();
#endif
return 0;
}

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

@@ -82,6 +82,7 @@ class Perft {


void score(const Board &board, Move move) {
local.node++;
std::cout << std::setw(16) << std::hex << board.get_hash() << std::endl;
#ifdef USE_FULL_COUNT
if (board.is_check()) local.check++;
if (move.is_capture()) local.capture++;