stellar

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

commit 37f488a52d4d9bd520d73e94fe8a8f21f6348e28
parent e611a16b9622e0b6831048b51a87cf51a2a01792
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date:   Sun, 13 Aug 2023 13:34:54 +0200

Improve scoring

Diffstat:
Msrc/engine/CMakeLists.txt | 1-
Msrc/engine/engine.cpp | 37++++++++++++++++++++++++++-----------
Dsrc/engine/score.cpp | 123-------------------------------------------------------------------------------
Msrc/engine/score.hpp | 10----------
Msrc/include/piece.hpp | 96++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
5 files changed, 121 insertions(+), 146 deletions(-)

diff --git a/src/engine/CMakeLists.txt b/src/engine/CMakeLists.txt @@ -1,6 +1,5 @@ add_executable(engine engine.cpp - score.cpp transposition.cpp ) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp @@ -29,16 +29,16 @@ int evaluate(const Board &board) { uint8_t square_i; int score = 0; - for (piece::Type type : piece::TypeIter()) { + for (const piece::Type type : piece::TypeIter()) { U64 bitboard = board.get_bitboard_piece(type); bitboard_for_each_bit(square_i, bitboard) { Square square = static_cast<Square>(square_i); if (bit_get(occupancy, square_i)) { - score += Score_value(type); - score += Score_position(type, side, square); + score += piece::score(type); + score += piece::score(type, side, square); } else { - score -= Score_value(type); - score -= Score_position(type, sideOther, square); + score -= piece::score(type); + score -= piece::score(type, sideOther, square); } } } @@ -98,7 +98,12 @@ int quiescence(Stats &stats, int alpha, int beta) { return 20000; } } - return Score_move(stats, move); + + const piece::Type type = move.piece().type; + if (move.is_capture()) return piece::score(type, move.piece_capture().type) + 10000; + if (stats.killer[0][stats.ply] == move) return 9000; + if (stats.killer[1][stats.ply] == move) return 8000; + return stats.history[to_underlying(type)][to_underlying(move.target())]; }; stats.follow_pv = pv_flag; @@ -147,11 +152,12 @@ int negamax(Stats &stats, int alpha, int beta, int depth, bool null) { if (isCheck) depth++; if (!pv_node && !isCheck) { + static constexpr const U32 score_pawn = piece::score(piece::Type::PAWN); int staticEval = evaluate(stats.board); // evaluation pruning if (depth < 3 && abs(beta - 1) > -MATE_VALUE + 100) { - int marginEval = Score_value(piece::Type::PAWN) * depth; + int marginEval = score_pawn * depth; if (staticEval - marginEval >= beta) return staticEval - marginEval; } @@ -165,21 +171,26 @@ int negamax(Stats &stats, int alpha, int beta, int depth, bool null) { } // razoring - score = staticEval + Score_value(piece::Type::PAWN); + score = staticEval + score_pawn; int scoreNew = quiescence(stats, alpha, beta); if (score < beta && depth == 1) { return (scoreNew > score) ? scoreNew : score; } - score += Score_value(piece::Type::PAWN); + score += score_pawn; if (score < beta && depth < 4) { if (scoreNew < beta) return (scoreNew > score) ? scoreNew : score; } } // futility pruning condition - static const int margin[] = {0, 100, 300, 500}; + static constexpr const int margin[] = { + 0, + piece::score(piece::Type::PAWN), + piece::score(piece::Type::KNIGHT), + piece::score(piece::Type::ROOK), + }; if (depth < 4 && abs(alpha) < MATE_SCORE && staticEval + margin[depth] <= alpha) futility = 1; } @@ -193,7 +204,11 @@ int negamax(Stats &stats, int alpha, int beta, int depth, bool null) { return 20000; } } - return Score_move(stats, move); + const piece::Type type = move.piece().type; + if (move.is_capture()) return piece::score(type, move.piece_capture().type) + 10000; + if (stats.killer[0][stats.ply] == move) return 9000; + if (stats.killer[1][stats.ply] == move) return 8000; + return stats.history[to_underlying(type)][to_underlying(move.target())]; }; stats.follow_pv = pv_flag; diff --git a/src/engine/score.cpp b/src/engine/score.cpp @@ -1,123 +0,0 @@ -#include "score.hpp" -#include "move.hpp" -#include "stats.hpp" -#include "utils_cpp.hpp" - -// clang-format off -struct Score_T { - int value; - int position[64]; - int capture[6]; -}; - -static const struct Score_T Scores[] = { -{ -.value = 100, -.position = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, -10, -10, 0, 0, 0, - 0, 0, 0, 5, 5, 0, 0, 0, - 5, 5, 10, 20, 20, 5, 5, 5, - 10, 10, 10, 20, 20, 10, 10, 10, - 20, 20, 20, 30, 30, 30, 20, 20, - 30, 30, 30, 40, 40, 30, 30, 30, - 90, 90, 90, 90, 90, 90, 90, 90, }, -.capture = { 105, 205, 305, 405, 505, 605} }, -{ -.value = 300, -.position = { - -5, -10 , 0, 0, 0, 0, -10, -5, - -5, 0, 0, 0, 0, 0, 0, -5, - -5, 5, 20, 10, 10, 20, 5, -5, - -5, 10, 20, 30, 30, 20, 10, -5, - -5, 10, 20, 30, 30, 20, 10, -5, - -5, 5, 20, 20, 20, 20, 5, -5, - -5, 0, 0, 10, 10, 0, 0, -5, - -5, 0, 0, 0, 0, 0, 0, -5, }, -.capture = { 104, 204, 304, 404, 504, 604} }, -{ -.value = 350, -.position = { - 0, 0, -10, 0, 0, -10, 0, 0, - 0, 30, 0, 0, 0, 0, 30, 0, - 0, 10, 0, 0, 0, 0, 10, 0, - 0, 0, 10, 20, 20, 10, 0, 0, - 0, 0, 10, 20, 20, 10, 0, 0, - 0, 0, 0, 10, 10, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, }, -.capture = { 103, 203, 303, 403, 503, 603} }, -{ -.value = 500, -.position = { - 0, 0, 0, 20, 20, 0, 0, 0, - 0, 0, 10, 20, 20, 10, 0, 0, - 0, 0, 10, 20, 20, 10, 0, 0, - 0, 0, 10, 20, 20, 10, 0, 0, - 0, 0, 10, 20, 20, 10, 0, 0, - 0, 0, 10, 20, 20, 10, 0, 0, - 50, 50, 50, 50, 50, 50, 50, 50, - 50, 50, 50, 50, 50, 50, 50, 50, }, -.capture = { 102, 202, 302, 402, 502, 602} }, -{ -.value = 1000, -.position = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, }, -.capture = { 101, 201, 301, 401, 501, 601} }, -{ -.value = 10000, -.position = { - 0, 0, 5, 0, -15, 0, 10, 0, - 0, 5, 5, -5, -5, 0, 5, 0, - 0, 0, 5, 10, 10, 5, 0, 0, - 0, 5, 10, 20, 20, 10, 5, 0, - 0, 5, 10, 20, 20, 10, 5, 0, - 0, 5, 5, 10, 10, 5, 5, 0, - 0, 0, 5, 5, 5, 5, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, }, -.capture = { 100, 200, 300, 400, 500, 600} }, -}; - -const Square mirror_score[128] = -{ - Square::a8, Square::b8, Square::c8, Square::d8, Square::e8, Square::f8, Square::g8, Square::h8, - Square::a7, Square::b7, Square::c7, Square::d7, Square::e7, Square::f7, Square::g7, Square::h7, - Square::a6, Square::b6, Square::c6, Square::d6, Square::e6, Square::f6, Square::g6, Square::h6, - Square::a5, Square::b5, Square::c5, Square::d5, Square::e5, Square::f5, Square::g5, Square::h5, - Square::a4, Square::b4, Square::c4, Square::d4, Square::e4, Square::f4, Square::g4, Square::h4, - Square::a3, Square::b3, Square::c3, Square::d3, Square::e3, Square::f3, Square::g3, Square::h3, - Square::a2, Square::b2, Square::c2, Square::d2, Square::e2, Square::f2, Square::g2, Square::h2, - Square::a1, Square::b1, Square::c1, Square::d1, Square::e1, Square::f1, Square::g1, Square::h1, Square::no_sq, -}; -// clang-format on - -int Score_value(piece::Type piece) { return Scores[to_underlying(piece)].value; } - -int Score_position(piece::Type piece, Color color, Square square) { - if (color == Color::BLACK) square = mirror_score[to_underlying(square)]; - return Scores[to_underlying(piece)].position[to_underlying(square)]; -} - -U32 Score_move(const Stats &stats, Move move) { - const int piece = to_underlying(move.piece().type); - const int capture = to_underlying(move.piece_capture().type); - - if (move.is_capture()) return Scores[piece].capture[capture] + 10000; - if (stats.killer[0][stats.ply] == move) return 9000; - if (stats.killer[1][stats.ply] == move) return 8000; - - return stats.history[piece][to_underlying(move.target())]; -} - -void Score_move_list(const Stats &stats, MoveList &list) { - for (auto &moveE : list) { - moveE.score = Score_move(stats, moveE.move); - } -} diff --git a/src/engine/score.hpp b/src/engine/score.hpp @@ -1,18 +1,8 @@ #ifndef STELLAR_SCORE_H #define STELLAR_SCORE_H -#include "board.hpp" -#include "movelist.hpp" -#include "stats.hpp" - #define SCORE_INFINITY 50000 #define MATE_VALUE 49000 #define MATE_SCORE 48000 -U32 Score_move(const Stats &stats, Move move); -void Score_move_list(const Stats &stats, MoveList &list); -int Score_position(piece::Type piece, Color color, Square square); -int Score_capture(piece::Type src, piece::Type tgt); -int Score_value(piece::Type piece); - #endif diff --git a/src/include/piece.hpp b/src/include/piece.hpp @@ -21,7 +21,7 @@ typedef Iterator<Type, Type::PAWN, Type::KING> TypeIter; class Piece { public: - constexpr U64 operator()(Square square, U64 occupancy) const { return attack(square, occupancy); } + constexpr U64 operator()(Square from, U64 occupancy) const { return attack(from, occupancy); } const Type type; const Color color; @@ -109,6 +109,100 @@ constexpr const Piece &get_from_code(char code) { constexpr const Piece &get_from_index(uint8_t index) { return table[index / 6][index % 6]; } +static inline constexpr const Square mirror[65] = { + // clang-format off + Square::a8, Square::b8, Square::c8, Square::d8, Square::e8, Square::f8, Square::g8, Square::h8, + Square::a7, Square::b7, Square::c7, Square::d7, Square::e7, Square::f7, Square::g7, Square::h7, + Square::a6, Square::b6, Square::c6, Square::d6, Square::e6, Square::f6, Square::g6, Square::h6, + Square::a5, Square::b5, Square::c5, Square::d5, Square::e5, Square::f5, Square::g5, Square::h5, + Square::a4, Square::b4, Square::c4, Square::d4, Square::e4, Square::f4, Square::g4, Square::h4, + Square::a3, Square::b3, Square::c3, Square::d3, Square::e3, Square::f3, Square::g3, Square::h3, + Square::a2, Square::b2, Square::c2, Square::d2, Square::e2, Square::f2, Square::g2, Square::h2, + Square::a1, Square::b1, Square::c1, Square::d1, Square::e1, Square::f1, Square::g1, Square::h1, Square::no_sq, + // clang-format on +}; + +static constexpr inline const uint16_t value[6] = {100, 300, 350, 500, 1000, 10000}; +static constexpr inline const uint16_t capture[6][6] = { + // clang-format off + {105, 205, 305, 405, 505, 605}, + {104, 204, 304, 404, 504, 604}, + {103, 203, 303, 403, 503, 603}, + {102, 202, 302, 402, 502, 602}, + {101, 201, 301, 401, 501, 601}, + {100, 200, 300, 400, 500, 600}, + // clang-format on +}; +static constexpr inline const int8_t position[6][64] = { + // clang-format off + { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, -10, -10, 0, 0, 0, + 0, 0, 0, 5, 5, 0, 0, 0, + 5, 5, 10, 20, 20, 5, 5, 5, + 10, 10, 10, 20, 20, 10, 10, 10, + 20, 20, 20, 30, 30, 30, 20, 20, + 30, 30, 30, 40, 40, 30, 30, 30, + 90, 90, 90, 90, 90, 90, 90, 90 + }, { + -5, -10 , 0, 0, 0, 0, -10, -5, + -5, 0, 0, 0, 0, 0, 0, -5, + -5, 5, 20, 10, 10, 20, 5, -5, + -5, 10, 20, 30, 30, 20, 10, -5, + -5, 10, 20, 30, 30, 20, 10, -5, + -5, 5, 20, 20, 20, 20, 5, -5, + -5, 0, 0, 10, 10, 0, 0, -5, + -5, 0, 0, 0, 0, 0, 0, -5 + }, { + 0, 0, -10, 0, 0, -10, 0, 0, + 0, 30, 0, 0, 0, 0, 30, 0, + 0, 10, 0, 0, 0, 0, 10, 0, + 0, 0, 10, 20, 20, 10, 0, 0, + 0, 0, 10, 20, 20, 10, 0, 0, + 0, 0, 0, 10, 10, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 + }, { + 0, 0, 0, 20, 20, 0, 0, 0, + 0, 0, 10, 20, 20, 10, 0, 0, + 0, 0, 10, 20, 20, 10, 0, 0, + 0, 0, 10, 20, 20, 10, 0, 0, + 0, 0, 10, 20, 20, 10, 0, 0, + 0, 0, 10, 20, 20, 10, 0, 0, + 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50 + }, { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 + }, { + 0, 0, 5, 0, -15, 0, 10, 0, + 0, 5, 5, -5, -5, 0, 5, 0, + 0, 0, 5, 10, 10, 5, 0, 0, + 0, 5, 10, 20, 20, 10, 5, 0, + 0, 5, 10, 20, 20, 10, 5, 0, + 0, 5, 5, 10, 10, 5, 5, 0, + 0, 0, 5, 5, 5, 5, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 + }, + // clang-format on +}; + +constexpr uint16_t score(Type piece) { return value[to_underlying(piece)]; } +constexpr uint16_t score(Type piece, Type captured) { + return capture[to_underlying(piece)][to_underlying(captured)]; +} + +constexpr int8_t score(Type type, Color color, Square square) { + if (color == Color::BLACK) square = mirror[to_underlying(square)]; + return position[to_underlying(type)][to_underlying(square)]; +} + } // namespace piece #endif