stellarUCI 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 11:34:54 +0200 |
Improve scoring
Diffstat:M | src/engine/CMakeLists.txt | | | - |
M | src/engine/engine.cpp | | | ++++++++++++++++++++++++++----------- |
D | src/engine/score.cpp | | | --------------------------------------------------------------------------------- |
M | src/engine/score.hpp | | | ---------- |
M | src/include/piece.hpp | | | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- |
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