stellar

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

commit 3b35974c0662fb2d1d5bc7bead88a5f53e0bee28
parent 3339ad957adba20630645faafc9751f114436587
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date:   Mon,  4 Sep 2023 22:41:33 +0200

Small refactor of pv table and uci

Diffstat:
MCMakeLists.txt | 2+-
Msrc/engine/CMakeLists.txt | 2+-
Msrc/engine/engine.cpp | 59+++++++++++++++++++++++++++++++++++++++--------------------
Msrc/engine/engine.hpp | 5++++-
Msrc/engine/uci.cpp | 22+++++-----------------
Msrc/engine/uci.hpp | 13++++++++-----
Msrc/move/move.cpp | 17+++++++++++------
Msrc/move/move.hpp | 1+
8 files changed, 70 insertions(+), 51 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt @@ -3,7 +3,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) project( Stellar - VERSION 0.0.33 + VERSION 0.0.34 DESCRIPTION "Chess engine written in C" HOMEPAGE_URL https://git.dimitrijedobrota.com/stellar.git LANGUAGES C CXX diff --git a/src/engine/CMakeLists.txt b/src/engine/CMakeLists.txt @@ -1,7 +1,7 @@ add_executable(engine evaluate.cpp - engine.cpp uci.cpp + engine.cpp ) target_link_libraries(engine diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp @@ -105,17 +105,43 @@ class RTable { const static int hashNull = 0; }; +class PVTable { + public: + Move best(uint8_t ply = 0) { return table[0][ply]; } + + void start(uint8_t ply) { length[ply] = ply; } + void store(Move move, uint8_t ply) { + table[ply][ply] = move; + for (uint8_t i = ply + 1; i < length[ply + 1]; i++) + table[ply][i] = table[ply + 1][i]; + length[ply] = length[ply + 1]; + } + + friend std::ostream &operator<<(std::ostream &os, const PVTable &pvtable); + + private: + Move table[MAX_PLY][MAX_PLY] = {{}}; + uint8_t length[MAX_PLY] = {0}; +}; + +std::ostream &operator<<(std::ostream &os, const PVTable &pvtable) { + for (uint8_t i = 0; i < pvtable.length[0]; i++) + os << pvtable.table[0][i] << " "; + return os; +} + static const uci::Settings *settings = nullptr; static Board board; static TTable ttable; static RTable rtable; -static Move pv_table[MAX_PLY][MAX_PLY]; + +static PVTable pvtable; + static Move killer[2][MAX_PLY]; static U32 history[12][64]; -static uint8_t pv_length[MAX_PLY]; static bool follow_pv; static U64 nodes; -static U32 ply; +static uint8_t ply; U32 inline move_list_score(Move move) { const piece::Type type = board.get_square_piece_type(move.source()); @@ -143,7 +169,7 @@ std::vector<int> move_list_sort(MoveList &list, const Move best) { if (!best_found && ply && follow_pv) { follow_pv = false; for (int i = 0; i < list.size(); i++) { - if (list[i] == pv_table[0][ply]) { + if (list[i] == pvtable.best(ply)) { score[i] = 20000; follow_pv = true; break; @@ -188,20 +214,12 @@ void stats_move_unmake(Board &copy, const Move move) { ply--; } -void stats_pv_store(Move move) { - pv_table[ply][ply] = move; - for (int i = ply + 1; i < pv_length[ply + 1]; i++) { - pv_table[ply][i] = pv_table[ply + 1][i]; - } - pv_length[ply] = pv_length[ply + 1]; -} - int16_t quiescence(int16_t alpha, int16_t beta) { if ((nodes & 2047) == 0) { uci::communicate(settings); if (settings->stopped) return 0; } - pv_length[ply] = ply; + pvtable.start(ply); nodes++; int score = evaluate::score_position(board); @@ -219,7 +237,7 @@ int16_t quiescence(int16_t alpha, int16_t beta) { if (score > alpha) { alpha = score; - stats_pv_store(move); + pvtable.store(move, ply); if (score >= beta) return beta; } @@ -240,7 +258,7 @@ int16_t negamax(int16_t alpha, int16_t beta, uint8_t depth, bool null) { uci::communicate(settings); if (settings->stopped) return 0; } - pv_length[ply] = ply; + pvtable.start(ply); // && fifty >= 100 if (ply && rtable.is_repetition(board.get_hash())) return 0; @@ -357,7 +375,7 @@ int16_t negamax(int16_t alpha, int16_t beta, uint8_t depth, bool null) { alpha = score; flag = Hashe::Flag::Exact; bestMove = move; - stats_pv_store(move); + pvtable.store(move, ply); if (score >= beta) { ttable.write(board, ply, bestMove, beta, depth, Hashe::Flag::Beta); @@ -404,8 +422,7 @@ Move search_position(const uci::Settings &settingsr) { settings->stopped = false; memset(killer, 0x00, sizeof(killer)); memset(history, 0x00, sizeof(history)); - memset(pv_table, 0x00, sizeof(pv_table)); - memset(pv_length, 0x00, sizeof(pv_length)); + rtable = RTable(); for (uint8_t depth = 1; depth <= settings->depth; depth++) { uci::communicate(settings); @@ -423,11 +440,13 @@ Move search_position(const uci::Settings &settingsr) { alpha = score - WINDOW; beta = score + WINDOW; - if (pv_length[0]) uci::pv_print(score, depth, nodes, pv_length, pv_table, board); + uci::pv_print(score, depth, nodes, pvtable); + if (settings->depth == 64 && uci::get_time_ms() >= (settings->stoptime + settings->starttime) / 2) + break; } settings->board = board; - return pv_table[0][0]; + return pvtable.best(); } } // namespace engine diff --git a/src/engine/engine.hpp b/src/engine/engine.hpp @@ -9,6 +9,9 @@ namespace engine { Move search_position(const uci::Settings &setting); -} +class PVTable; +std::ostream &operator<<(std::ostream &os, const PVTable &pvtable); + +} // namespace engine #endif diff --git a/src/engine/uci.cpp b/src/engine/uci.cpp @@ -9,19 +9,14 @@ #include "uci.hpp" namespace uci { + uint32_t get_time_ms(void) { struct timeval time; gettimeofday(&time, NULL); return time.tv_sec * 1000 + time.tv_usec / 1000; } -void move_print(const Board &board, Move move) { - std::cout << square::to_coordinates(move.source()) << square::to_coordinates(move.target()); - if (move.is_promote()) std::cout << piece::get_code(move.promoted(), board.get_side()); -} - -void pv_print(int16_t score, uint8_t depth, uint64_t nodes, uint8_t pv_length[MAX_PLY], - Move pv_table[MAX_PLY][MAX_PLY], const Board &board) { +void pv_print(int16_t score, uint8_t depth, uint64_t nodes, const engine::PVTable &pvtable) { if (score > -MATE_VALUE && score < -MATE_SCORE) { std::cout << "info score mate " << -(score + MATE_VALUE) / 2 - 1; } else if (score > MATE_SCORE && score < MATE_VALUE) { @@ -32,12 +27,7 @@ void pv_print(int16_t score, uint8_t depth, uint64_t nodes, uint8_t pv_length[MA std::cout << " depth " << (unsigned)depth; std::cout << " nodes " << nodes; - std::cout << " pv "; - for (int i = 0; i < pv_length[0]; i++) { - uci::move_print(board, pv_table[0][i]); - std::cout << " "; - } - std::cout << "\n"; + std::cout << " pv " << pvtable << "\n"; } void communicate(const uci::Settings *settings) { @@ -110,7 +100,7 @@ void loop(void) { } else if (command == "go") { settings.searchMoves.clear(); uint32_t wtime = 0, btime = 0, movetime = 0; - uint16_t winc = 0, binc = 0, movestogo = 30; + uint16_t winc = 0, binc = 0, movestogo = 60; while (iss >> command) { if (command == "wtime") @@ -162,9 +152,7 @@ void loop(void) { if (!time) settings.infinite = true; const Move best = engine::search_position(settings); - std::cout << "bestmove "; - uci::move_print(settings.board, best); - std::cout << "\n"; + std::cout << "bestmove " << best << '\n'; settings.newgame = false; } diff --git a/src/engine/uci.hpp b/src/engine/uci.hpp @@ -7,6 +7,12 @@ #include "score.hpp" #include "utils.hpp" +namespace engine { + +class PVTable; + +} // namespace engine + namespace uci { struct Settings { @@ -30,12 +36,9 @@ struct Settings { }; void loop(void); -void pv_print(int16_t score, uint8_t depth, uint64_t nodes, uint8_t pv_length[MAX_PLY], - Move pv_table[MAX_PLY][MAX_PLY], const Board &board); -void move_print(const Board &board, Move move); -void communicate(const uci::Settings *settings); uint32_t get_time_ms(void); +void communicate(const uci::Settings *settings); +void pv_print(int16_t score, uint8_t depth, uint64_t nodes, const engine::PVTable &pvtable); } // namespace uci - #endif diff --git a/src/move/move.cpp b/src/move/move.cpp @@ -93,13 +93,18 @@ bool Move::make(Board &board) const { return 0; } +void Move::print(void) const { + std::cout << square::to_coordinates(source()) << " "; + std::cout << square::to_coordinates(target()) << " "; + std::cout << (is_promote() ? piece::get_code(promoted()) : '.') << " "; + std::cout << is_double() << " "; + std::cout << is_enpassant() << " "; + std::cout << is_castle(); +} + std::ostream &operator<<(std::ostream &os, Move move) { - os << square::to_coordinates(move.source()) << " "; - os << square::to_coordinates(move.target()) << " "; - os << (move.is_promote() ? piece::get_code(move.promoted()) : '.') << " "; - os << move.is_double() << " "; - os << move.is_enpassant() << " "; - os << move.is_castle(); + std::cout << square::to_coordinates(move.source()) << square::to_coordinates(move.target()); + if (move.is_promote()) std::cout << piece::get_code(move.promoted()); return os; } diff --git a/src/move/move.hpp b/src/move/move.hpp @@ -56,6 +56,7 @@ struct Move { bool make(Board &board) const; friend std::ostream &operator<<(std::ostream &os, Move move); + void print(void) const; private: inline void piece_remove(Board &board, piece::Type type, color::Color color, square::Square square) const;