stellar

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:
MCMakeLists.txt | 2+-
Msrc/engine/CMakeLists.txt | 4++++
Msrc/engine/engine.cpp | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
Msrc/perft/perft.cpp | 1+
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++;