stellarUCI Chess engine written in C++20 |
git clone git://git.dimitrijedobrota.com/stellar.git |
Log | Files | Refs | README | LICENSE | |
commit | 478983d07da27cc277fef32f73a65f5de5631f1a |
parent | c36cee0f9d0031a7c068cab56947327f2a199c1e |
author | Dimitrije Dobrota <mail@dimitrijedobrota.com> |
date | Mon, 28 Aug 2023 19:34:58 +0200 |
Restructure engine
Diffstat:M | CMakeLists.txt | | | +- |
M | src/engine/CMakeLists.txt | | | +++++++- |
M | src/engine/engine.cpp | | | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------- |
M | src/engine/score.hpp | | | +++--- |
D | src/engine/transposition.cpp | | | ---------------------------------- |
D | src/engine/transposition.hpp | | | ----------------------------------------- |
M | src/engine/uci.cpp | | | + |
M | src/engine/uci.hpp | | | + |
8 files changed, 85 insertions(+), 89 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
@@ -3,7 +3,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
project(
Stellar
VERSION 0.0.23
VERSION 0.0.24
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,6 +1,5 @@
add_executable(engine
engine.cpp
transposition.cpp
uci.cpp
)
@@ -12,6 +11,13 @@ target_link_libraries(engine
PRIVATE utils
)
stellar_target_precompile_headers(board
PRIVATE "board.hpp"
PRIVATE "move.hpp"
PRIVATE "movelist.hpp"
PRIVATE "piece.hpp"
)
set_target_properties(engine PROPERTIES
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp
@@ -10,7 +10,6 @@
#include "movelist.hpp"
#include "piece.hpp"
#include "score.hpp"
#include "transposition.hpp"
#include "uci.hpp"
#include "utils.hpp"
@@ -23,8 +22,62 @@
namespace engine {
struct Hashe {
enum class Flag : uint8_t {
Exact,
Alpha,
Beta
};
U64 key;
Move best;
uint8_t depth;
int16_t score;
Flag flag;
};
class TTable {
public:
static inline constexpr const uint16_t unknown = 32500;
TTable() {}
TTable(U64 size) : table(size, {0}) {}
void clear() { table.clear(); };
int16_t read(const Board &board, int ply, Move *best, int16_t alpha, int16_t beta, uint8_t depth) const {
U64 hash = board.get_hash();
const Hashe &phashe = table[hash % table.size()];
if (phashe.key == hash) {
if (phashe.depth >= depth) {
int16_t score = phashe.score;
if (score < -MATE_SCORE) score += ply;
if (score > MATE_SCORE) score -= ply;
if (phashe.flag == Hashe::Flag::Exact) return score;
if ((phashe.flag == Hashe::Flag::Alpha) && (score <= alpha)) return alpha;
if ((phashe.flag == Hashe::Flag::Beta) && (score >= beta)) return beta;
}
*best = phashe.best;
}
return unknown;
}
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()];
if (score < -MATE_SCORE) score += ply;
if (score > MATE_SCORE) score -= ply;
phashe = {hash, best, depth, score, flag};
}
private:
std::vector<Hashe> table;
};
Board board;
TTable ttable(C64(0x400000));
TTable ttable;
Move pv_table[MAX_PLY][MAX_PLY];
Move killer[2][MAX_PLY];
U32 history[12][64];
@@ -130,7 +183,7 @@ void stats_pv_store(Move move) {
pv_length[ply] = pv_length[ply + 1];
}
int quiescence(int alpha, int beta) {
int quiescence(int16_t alpha, int16_t beta) {
pv_length[ply] = ply;
nodes++;
@@ -159,9 +212,9 @@ int quiescence(int alpha, int beta) {
return alpha;
}
int negamax(int alpha, int beta, uint8_t depth, bool null) {
int negamax(int16_t alpha, int16_t beta, uint8_t depth, bool null) {
int pv_node = (beta - alpha) > 1;
HasheFlag flag = HasheFlag::Alpha;
Hashe::Flag flag = Hashe::Flag::Alpha;
int futility = 0;
Move bestMove;
Board copy;
@@ -169,7 +222,7 @@ int negamax(int alpha, int beta, uint8_t depth, bool null) {
pv_length[ply] = ply;
int score = ttable.read(board, ply, &bestMove, alpha, beta, depth);
if (ply && score != TTABLE_UNKNOWN && !pv_node) return score;
if (ply && score != TTable::unknown && !pv_node) return score;
// && fifty >= 100
if (ply && is_repetition()) return 0;
@@ -280,12 +333,12 @@ int negamax(int alpha, int beta, uint8_t depth, bool null) {
}
alpha = score;
flag = HasheFlag::Exact;
flag = Hashe::Flag::Exact;
bestMove = move;
stats_pv_store(move);
if (score >= beta) {
ttable.write(board, ply, bestMove, beta, depth, HasheFlag::Beta);
ttable.write(board, ply, bestMove, beta, depth, Hashe::Flag::Beta);
if (!move.is_capture()) {
killer[1][ply] = killer[0][ply];
@@ -309,10 +362,20 @@ int negamax(int alpha, int beta, uint8_t depth, bool null) {
}
void search_position(const uci::Settings &setting) {
int alpha = -SCORE_INFINITY, beta = SCORE_INFINITY;
int16_t alpha = -SCORE_INFINITY, beta = SCORE_INFINITY;
if (setting.newgame) {
ttable = TTable(C64(0x400000));
}
ply = 0;
nodes = 0;
board = setting.board;
memset(killer, 0x00, sizeof(killer));
memset(history, 0x00, sizeof(history));
memset(pv_table, 0x00, sizeof(pv_table));
memset(pv_length, 0x00, sizeof(pv_length));
for (uint8_t depth_crnt = 1; depth_crnt <= setting.depth;) {
follow_pv = 1;
diff --git a/src/engine/score.hpp b/src/engine/score.hpp
@@ -1,8 +1,8 @@
#ifndef STELLAR_SCORE_H
#define STELLAR_SCORE_H
#define SCORE_INFINITY 50000
#define MATE_VALUE 49000
#define MATE_SCORE 48000
#define SCORE_INFINITY 32000
#define MATE_VALUE 31000
#define MATE_SCORE 30000
#endif
diff --git a/src/engine/transposition.cpp b/src/engine/transposition.cpp
@@ -1,34 +0,0 @@
#include "transposition.hpp"
#include "board.hpp"
#include "score.hpp"
int TTable::read(const Board &board, int ply, Move *best, int alpha, int beta, uint8_t depth) const {
U64 hash = board.get_hash();
const Hashe &phashe = table[hash % table.size()];
if (phashe.key == hash) {
if (phashe.depth >= depth) {
int score = phashe.score;
if (score < -MATE_SCORE) score += ply;
if (score > MATE_SCORE) score -= ply;
if (phashe.flag == HasheFlag::Exact) return score;
if ((phashe.flag == HasheFlag::Alpha) && (score <= alpha)) return alpha;
if ((phashe.flag == HasheFlag::Beta) && (score >= beta)) return beta;
}
*best = phashe.best;
}
return TTABLE_UNKNOWN;
}
void TTable::write(const Board &board, int ply, Move best, int score, uint8_t depth, HasheFlag flag) {
U64 hash = board.get_hash();
Hashe &phashe = table[hash % table.size()];
if (score < -MATE_SCORE) score += ply;
if (score > MATE_SCORE) score -= ply;
phashe = {hash, best, depth, score, flag};
}
diff --git a/src/engine/transposition.hpp b/src/engine/transposition.hpp
@@ -1,41 +0,0 @@
#ifndef STELLAR_TRANSPOSITION_H
#define STELLAR_TRANSPOSITION_H
#include "move.hpp"
#include "utils.hpp"
#include <vector>
#define TTABLE_UNKNOWN 100000
#define T TTable
enum class HasheFlag : uint8_t {
Exact,
Alpha,
Beta
};
typedef struct Hashe Hashe;
struct Hashe {
U64 key;
Move best;
uint8_t depth;
int score;
HasheFlag flag;
};
class TTable {
public:
TTable(U64 size) : table(size, {0}) {}
void clear() { table.clear(); };
int read(const Board &board, int ply, Move *best, int alpha, int beta, uint8_t depth) const;
void write(const Board &board, int ply, Move best, int score, uint8_t depth, HasheFlag flag);
private:
std::vector<Hashe> table;
};
#undef T
#endif
diff --git a/src/engine/uci.cpp b/src/engine/uci.cpp
@@ -101,6 +101,7 @@ void loop(void) {
}
}
engine::search_position(settings);
settings.newgame = false;
}
}
}
diff --git a/src/engine/uci.hpp b/src/engine/uci.hpp
@@ -22,6 +22,7 @@ struct Settings {
bool debug = false;
bool mate = false;
bool infinite = false;
bool newgame = true;
};
void loop(void);