stellar

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

commit478983d07da27cc277fef32f73a65f5de5631f1a
parentc36cee0f9d0031a7c068cab56947327f2a199c1e
authorDimitrije Dobrota <mail@dimitrijedobrota.com>
dateMon, 28 Aug 2023 19:34:58 +0200

Restructure engine

Diffstat:
MCMakeLists.txt|+-
Msrc/engine/CMakeLists.txt|+++++++-
Msrc/engine/engine.cpp|++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
Msrc/engine/score.hpp|+++---
Dsrc/engine/transposition.cpp|----------------------------------
Dsrc/engine/transposition.hpp|-----------------------------------------
Msrc/engine/uci.cpp|+
Msrc/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);