commit ef1ae825fa1a9d9fd748e925715d7f0ec8177786
parent fefa1caf09190a7a6c45541e6e5496e73d9ca9f3
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date: Sun, 13 Aug 2023 15:41:53 +0200
Use global variables instead of stats in engine
Diffstat:
4 files changed, 111 insertions(+), 135 deletions(-)
diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp
@@ -8,18 +8,26 @@
#include "move.hpp"
#include "movelist.hpp"
#include "score.hpp"
-#include "stats.hpp"
#include "transposition.hpp"
#include "utils_cpp.hpp"
#include "zobrist.hpp"
+#define MAX_PLY 64
#define FULL_DEPTH 4
#define REDUCTION_LIMIT 3
#define REDUCTION_MOVE 2
#define WINDOW 50
-/* SEARCHING */
+Board board;
+TTable ttable(C64(0x400000));
+Move pv_table[MAX_PLY][MAX_PLY];
+Move killer[2][MAX_PLY];
+U32 history[16][64];
+int pv_length[MAX_PLY];
+int follow_pv;
+long nodes;
+int ply;
int evaluate(const Board &board) {
Color side = board.get_side();
@@ -48,52 +56,51 @@ int evaluate(const Board &board) {
int is_repetition() { return 0; }
-int stats_move_make(Stats &stats, Board ©, Move move, int flag) {
- copy = stats.board;
- if (!move.make(stats.board, flag)) {
- stats.board = copy;
+int stats_move_make(Board ©, Move move, int flag) {
+ copy = board;
+ if (!move.make(board, flag)) {
+ board = copy;
return 0;
}
- stats.ply++;
+ ply++;
return 1;
}
-void stats_move_make_pruning(Stats &stats, Board ©) {
- copy = stats.board;
- stats.board.switch_side();
- stats.board.set_enpassant(Square::no_sq);
- stats.ply++;
+void stats_move_make_pruning(Board ©) {
+ copy = board;
+ board.switch_side();
+ board.set_enpassant(Square::no_sq);
+ ply++;
}
-void stats_move_unmake(Stats &stats, Board ©) {
- stats.board = copy;
- stats.ply--;
+void stats_move_unmake(Board ©) {
+ board = copy;
+ ply--;
}
-void stats_pv_store(Stats &stats, Move move) {
- const int ply = stats.ply;
- stats.pv_table[ply][ply] = move;
- for (int i = ply + 1; i < stats.pv_length[ply + 1]; i++) {
- stats.pv_table[ply][i] = stats.pv_table[ply + 1][i];
+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];
}
- stats.pv_length[ply] = stats.pv_length[ply + 1];
+ pv_length[ply] = pv_length[ply + 1];
}
-int quiescence(Stats &stats, int alpha, int beta) {
- stats.pv_length[stats.ply] = stats.ply;
- stats.nodes++;
+int quiescence(int alpha, int beta) {
+ pv_length[ply] = ply;
+ nodes++;
- int score = evaluate(stats.board);
- if (stats.ply > MAX_PLY - 1) return score;
+ int score = evaluate(board);
+ if (ply > MAX_PLY - 1) return score;
if (score >= beta) return beta;
if (score > alpha) alpha = score;
Board copy;
bool pv_flag = false;
- const auto score_move = [&stats, &pv_flag](Move move) -> U32 {
- if (stats.ply && stats.follow_pv) {
- stats.follow_pv = 0;
- if (stats.pv_table[0][stats.ply] == move) {
+ const auto score_move = [&pv_flag](Move move) -> U32 {
+ if (ply && follow_pv) {
+ follow_pv = 0;
+ if (pv_table[0][ply] == move) {
pv_flag = true;
return 20000;
}
@@ -101,20 +108,20 @@ int quiescence(Stats &stats, int alpha, int beta) {
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())];
+ if (killer[0][ply] == move) return 9000;
+ if (killer[1][ply] == move) return 8000;
+ return history[to_underlying(type)][to_underlying(move.target())];
};
- stats.follow_pv = pv_flag;
+ follow_pv = pv_flag;
- for (const auto [move, _] : MoveList(stats.board, score_move)) {
- if (!stats_move_make(stats, copy, move, 1)) continue;
- score = -quiescence(stats, -beta, -alpha);
- stats_move_unmake(stats, copy);
+ for (const auto [move, _] : MoveList(board, score_move)) {
+ if (!stats_move_make(copy, move, 1)) continue;
+ score = -quiescence(-beta, -alpha);
+ stats_move_unmake(copy);
if (score > alpha) {
alpha = score;
- stats_pv_store(stats, move);
+ stats_pv_store(move);
if (score >= beta) return beta;
}
}
@@ -122,38 +129,38 @@ int quiescence(Stats &stats, int alpha, int beta) {
return alpha;
}
-int negamax(Stats &stats, int alpha, int beta, int depth, bool null) {
+int negamax(int alpha, int beta, int depth, bool null) {
int pv_node = (beta - alpha) > 1;
HasheFlag flag = HasheFlag::Alpha;
int futility = 0;
Move bestMove;
Board copy;
- stats.pv_length[stats.ply] = stats.ply;
+ pv_length[ply] = ply;
- int score = stats.ttable.read(stats, &bestMove, alpha, beta, depth);
- if (stats.ply && score != TTABLE_UNKNOWN && !pv_node) return score;
+ int score = ttable.read(board, ply, &bestMove, alpha, beta, depth);
+ if (ply && score != TTABLE_UNKNOWN && !pv_node) return score;
// && fifty >= 100
- if (stats.ply && is_repetition()) return 0;
+ if (ply && is_repetition()) return 0;
if (depth == 0) {
- stats.nodes++;
- int score = quiescence(stats, alpha, beta);
- // ttable_write(stats, bestMove, score, depth, HasheFlag::Exact);
+ nodes++;
+ int score = quiescence(alpha, beta);
+ // ttable_write(board, ply, bestMove, score, depth, HasheFlag::Exact);
return score;
}
if (alpha < -MATE_VALUE) alpha = -MATE_VALUE;
if (beta > MATE_VALUE - 1) beta = MATE_VALUE - 1;
if (alpha >= beta) return alpha;
- // if (stats.ply > MAX_PLY - 1) return evaluate(stats.board);
+ // if (ply > MAX_PLY - 1) return evaluate(board);
- int isCheck = stats.board.is_check();
+ int isCheck = board.is_check();
if (isCheck) depth++;
if (!pv_node && !isCheck) {
static constexpr const U32 score_pawn = piece::score(piece::Type::PAWN);
- int staticEval = evaluate(stats.board);
+ int staticEval = evaluate(board);
// evaluation pruning
if (depth < 3 && abs(beta - 1) > -MATE_VALUE + 100) {
@@ -163,16 +170,16 @@ int negamax(Stats &stats, int alpha, int beta, int depth, bool null) {
if (null) {
// null move pruning
- if (stats.ply && depth > 2 && staticEval >= beta) {
- stats_move_make_pruning(stats, copy);
- score = -negamax(stats, -beta, -beta + 1, depth - 1 - REDUCTION_MOVE, false);
- stats_move_unmake(stats, copy);
+ if (ply && depth > 2 && staticEval >= beta) {
+ stats_move_make_pruning(copy);
+ score = -negamax(-beta, -beta + 1, depth - 1 - REDUCTION_MOVE, false);
+ stats_move_unmake(copy);
if (score >= beta) return beta;
}
// razoring
score = staticEval + score_pawn;
- int scoreNew = quiescence(stats, alpha, beta);
+ int scoreNew = quiescence(alpha, beta);
if (score < beta && depth == 1) {
return (scoreNew > score) ? scoreNew : score;
@@ -195,79 +202,75 @@ int negamax(Stats &stats, int alpha, int beta, int depth, bool null) {
}
bool pv_flag = false;
- const auto score_move = [&stats, &bestMove, &pv_flag](Move move) -> U32 {
+ const auto score_move = [&bestMove, &pv_flag](Move move) -> U32 {
if (move == bestMove) return 30000;
- if (stats.ply && stats.follow_pv) {
- stats.follow_pv = 0;
- if (stats.pv_table[0][stats.ply] == move) {
+ if (ply && follow_pv) {
+ follow_pv = 0;
+ if (pv_table[0][ply] == move) {
pv_flag = true;
return 20000;
}
}
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())];
+ if (killer[0][ply] == move) return 9000;
+ if (killer[1][ply] == move) return 8000;
+ return history[to_underlying(type)][to_underlying(move.target())];
};
- stats.follow_pv = pv_flag;
+ follow_pv = pv_flag;
int legal_moves = 0;
int searched = 0;
- for (const auto [move, _] : MoveList(stats.board, score_move)) {
- if (!stats_move_make(stats, copy, move, 0)) continue;
+ for (const auto [move, _] : MoveList(board, score_move)) {
+ if (!stats_move_make(copy, move, 0)) continue;
legal_moves++;
// futility pruning
- if (futility && searched && !move.is_capture() && !move.is_promote() && !stats.board.is_check()) {
- stats_move_unmake(stats, copy);
+ if (futility && searched && !move.is_capture() && !move.is_promote() && !board.is_check()) {
+ stats_move_unmake(copy);
continue;
}
if (!searched) {
- score = -negamax(stats, -beta, -alpha, depth - 1, true);
+ score = -negamax(-beta, -alpha, depth - 1, true);
} else {
// Late Move Reduction
if (!pv_node && searched >= FULL_DEPTH && depth >= REDUCTION_LIMIT && !isCheck &&
!move.is_capture() && !move.is_promote() &&
- (move.source() != stats.killer[0][stats.ply].source() ||
- move.target() != stats.killer[0][stats.ply].target()) &&
- (move.source() != stats.killer[1][stats.ply].source() ||
- move.target() != stats.killer[1][stats.ply].target())) {
- score = -negamax(stats, -alpha - 1, -alpha, depth - 2, true);
+ (move.source() != killer[0][ply].source() || move.target() != killer[0][ply].target()) &&
+ (move.source() != killer[1][ply].source() || move.target() != killer[1][ply].target())) {
+ score = -negamax(-alpha - 1, -alpha, depth - 2, true);
} else
score = alpha + 1;
- // found better move
// Principal Variation Search
if (score > alpha) {
- score = -negamax(stats, -alpha - 1, -alpha, depth - 1, true);
+ score = -negamax(-alpha - 1, -alpha, depth - 1, true);
// if fail research
- if ((score > alpha) && (score < beta))
- score = -negamax(stats, -beta, -alpha, depth - 1, true);
+ if ((score > alpha) && (score < beta)) score = -negamax(-beta, -alpha, depth - 1, true);
}
}
- stats_move_unmake(stats, copy);
+ stats_move_unmake(copy);
searched++;
if (score > alpha) {
if (!move.is_capture()) {
- stats.history[move.piece().index][to_underlying(move.target())] += depth;
+ history[move.piece().index][to_underlying(move.target())] += depth;
}
alpha = score;
flag = HasheFlag::Exact;
bestMove = move;
- stats_pv_store(stats, move);
+ stats_pv_store(move);
if (score >= beta) {
- stats.ttable.write(stats, bestMove, beta, depth, HasheFlag::Beta);
+ ttable.write(board, ply, bestMove, beta, depth, HasheFlag::Beta);
if (!move.is_capture()) {
- stats.killer[1][stats.ply] = stats.killer[0][stats.ply];
- stats.killer[0][stats.ply] = move;
+ killer[1][ply] = killer[0][ply];
+ killer[0][ply] = move;
}
return beta;
@@ -277,12 +280,12 @@ int negamax(Stats &stats, int alpha, int beta, int depth, bool null) {
if (legal_moves == 0) {
if (isCheck)
- return -MATE_VALUE + stats.ply;
+ return -MATE_VALUE + ply;
else
return 0;
}
- stats.ttable.write(stats, bestMove, alpha, depth, flag);
+ ttable.write(board, ply, bestMove, alpha, depth, flag);
return alpha;
}
@@ -291,15 +294,12 @@ void move_print_UCI(Move move) {
if (move.is_promote()) std::cout << move.piece_promote().code;
}
-TTable ttable(C64(0x400000));
-void search_position(Board &board, int depth) {
- Stats stats = {ttable, board};
-
+void search_position(int depth) {
int alpha = -SCORE_INFINITY, beta = SCORE_INFINITY;
for (int crnt = 1; crnt <= depth;) {
- stats.follow_pv = 1;
+ follow_pv = 1;
- int score = negamax(stats, alpha, beta, crnt, true);
+ int score = negamax(alpha, beta, crnt, true);
if ((score <= alpha) || (score >= beta)) {
alpha = -SCORE_INFINITY;
beta = SCORE_INFINITY;
@@ -308,7 +308,7 @@ void search_position(Board &board, int depth) {
alpha = score - WINDOW;
beta = score + WINDOW;
- if (stats.pv_length[0]) {
+ if (pv_length[0]) {
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) {
@@ -318,10 +318,10 @@ void search_position(Board &board, int depth) {
}
std::cout << " depth " << crnt;
- std::cout << " nodes " << stats.nodes;
+ std::cout << " nodes " << nodes;
std::cout << " pv ";
- for (int i = 0; i < stats.pv_length[0]; i++) {
- move_print_UCI(stats.pv_table[0][i]);
+ for (int i = 0; i < pv_length[0]; i++) {
+ move_print_UCI(pv_table[0][i]);
std::cout << " ";
}
std::cout << "\n";
@@ -330,7 +330,7 @@ void search_position(Board &board, int depth) {
}
std::cout << "bestmove ";
- move_print_UCI(stats.pv_table[0][0]);
+ move_print_UCI(pv_table[0][0]);
std::cout << "\n";
}
@@ -393,7 +393,7 @@ char *Instruction_token_n(Instruction *self, int n) {
char *Instruction_token_next(Instruction *self) { return Instruction_token_n(self, 1); }
-Move parse_move(const Board &board, char *move_string) {
+Move parse_move(char *move_string) {
Square source = square_from_coordinates(move_string);
Square target = square_from_coordinates(move_string + 2);
@@ -408,7 +408,7 @@ Move parse_move(const Board &board, char *move_string) {
return {};
}
-Board *Instruction_parse(Instruction *self, Board &board) {
+Board *Instruction_parse(Instruction *self) {
char *token = Instruction_token(self);
do {
@@ -435,14 +435,13 @@ Board *Instruction_parse(Instruction *self, Board &board) {
if (strcmp(token, "moves") == 0) {
while ((token = Instruction_token_next(self))) {
- Move move = parse_move(board, token);
+ Move move = parse_move(token);
if (move == Move()) {
move.make(board, 0);
} else {
printf("Invalid move %s!\n", token);
}
}
- // board_print(board);
return &board;
}
@@ -457,7 +456,7 @@ Board *Instruction_parse(Instruction *self, Board &board) {
// printf("Unknown argument %s after go\n", token);
}
}
- search_position(board, depth);
+ search_position(depth);
continue;
}
@@ -490,7 +489,7 @@ void uci_loop(void) {
if (!fgets(input, sizeof(input), stdin)) continue;
instruction = Instruction_new(input);
- if (!Instruction_parse(instruction, board)) break;
+ if (!Instruction_parse(instruction)) break;
Instruction_free(&instruction);
}
diff --git a/src/engine/stats.hpp b/src/engine/stats.hpp
@@ -1,22 +0,0 @@
-#ifndef STELLAR_STATS_H
-#define STELLAR_STATS_H
-
-#include "move.hpp"
-#include "utils_cpp.hpp"
-
-#define MAX_PLY 64
-
-typedef struct Stats Stats;
-struct Stats {
- struct TTable &ttable;
- Board &board;
- Move pv_table[MAX_PLY][MAX_PLY];
- Move killer[2][MAX_PLY];
- U32 history[16][64];
- int pv_length[MAX_PLY];
- int follow_pv;
- long nodes;
- int ply;
-};
-
-#endif
diff --git a/src/engine/transposition.cpp b/src/engine/transposition.cpp
@@ -2,16 +2,16 @@
#include "board.hpp"
#include "score.hpp"
-int TTable::read(const Stats &stats, Move *best, int alpha, int beta, int depth) const {
+int TTable::read(const Board &board, int ply, Move *best, int alpha, int beta, int depth) const {
- U64 hash = stats.board.get_hash();
+ 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 += stats.ply;
- if (score > MATE_SCORE) score -= stats.ply;
+ 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;
@@ -22,13 +22,13 @@ int TTable::read(const Stats &stats, Move *best, int alpha, int beta, int depth)
return TTABLE_UNKNOWN;
}
-void TTable::write(const Stats &stats, Move best, int score, int depth, HasheFlag flag) {
+void TTable::write(const Board &board, int ply, Move best, int score, int depth, HasheFlag flag) {
- U64 hash = stats.board.get_hash();
+ U64 hash = board.get_hash();
Hashe &phashe = table[hash % table.size()];
- if (score < -MATE_SCORE) score += stats.ply;
- if (score > MATE_SCORE) score -= stats.ply;
+ 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
@@ -2,7 +2,6 @@
#define STELLAR_TRANSPOSITION_H
#include "move.hpp"
-#include "stats.hpp"
#include "utils_cpp.hpp"
#include <vector>
@@ -31,8 +30,8 @@ class TTable {
TTable(U64 size) : table(size, {0}) {}
void clear() { table.clear(); };
- void write(const Stats &stats, Move best, int score, int depth, HasheFlag flag);
- int read(const Stats &stats, Move *best, int alpha, int beta, int depth) const;
+ int read(const Board &board, int ply, Move *best, int alpha, int beta, int depth) const;
+ void write(const Board &board, int ply, Move best, int score, int depth, HasheFlag flag);
private:
std::vector<Hashe> table;