From 4b47b3028e2fb195de596cd0ee3454fd4fba4d66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Silveira?= Date: Mon, 11 Jul 2022 16:55:32 +0100 Subject: [PATCH 1/3] added pv search (#31) --- README.md | 1 + src/engine/movepicker/movepicker.cpp | 33 ++++++++++++++++++++-------- src/engine/movepicker/movepicker.hpp | 10 ++++++--- src/interfaces/uci/uci.cpp | 4 ++-- 4 files changed, 34 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 14b780a..f603352 100644 --- a/README.md +++ b/README.md @@ -34,3 +34,4 @@ Engine Features - History Move Heuristic - Triangular PV-Table - Iterative Deepening +- PV Sorting diff --git a/src/engine/movepicker/movepicker.cpp b/src/engine/movepicker/movepicker.cpp index 33f8cb8..026b9fc 100644 --- a/src/engine/movepicker/movepicker.cpp +++ b/src/engine/movepicker/movepicker.cpp @@ -13,7 +13,7 @@ #define MIN_EVAL (INT_MIN + 1) -int MovePicker::score(const Move &move) const +int MovePicker::score(const Move &move) { // clang-format off static const int MVV_LVA[6][6] = { @@ -26,6 +26,11 @@ int MovePicker::score(const Move &move) const }; // clang-format on + if (_pv_table[0][_current_depth] == move.getEncoded()) + { + return 20000; + } + if (move.isCapture()) { return MVV_LVA[move.getPiece()][move.getCapturedPiece()]; @@ -238,6 +243,12 @@ void MovePicker::addToPrincipalVariation(Move const &move) _pv_length[_current_depth] = _pv_length[_current_depth + 1]; } +void MovePicker::clearSearchCounters() +{ + _current_nodes = 0; + _current_depth = 0; +} + // Public Methods int MovePicker::getMaxDepth() const @@ -257,14 +268,13 @@ void MovePicker::setMaxDepth(int depth) MovePicker::SearchResult MovePicker::findBestMove() { - this->clearState(); + this->clearTables(); // Iterative Deepening - int alpha = 0; + int alpha; for (int depth = 1; depth <= _max_depth; depth++) { - _current_nodes = 0; - _current_depth = 0; + this->clearSearchCounters(); alpha = search(depth); } @@ -273,18 +283,23 @@ MovePicker::SearchResult MovePicker::findBestMove() return res; } +/** + * @brief This function corresponds to one of + * the loops of findBestMove() + * + * @param depth + * @return MovePicker::SearchResult + */ MovePicker::SearchResult MovePicker::findBestMove(int depth) { - _current_nodes = 0; - _current_depth = 0; - + this->clearSearchCounters(); int alpha = search(depth); SearchResult res = SearchResult{alpha, _current_nodes, _pv_length[0]}; memcpy(&res.pv, &_pv_table[0], (unsigned long)_pv_length[0] * sizeof(int)); return res; } -void MovePicker::clearState() +void MovePicker::clearTables() { memset(_history_moves, 0, sizeof(_history_moves)); memset(_killer_moves, 0, sizeof(_killer_moves)); diff --git a/src/engine/movepicker/movepicker.hpp b/src/engine/movepicker/movepicker.hpp index 1e5bca9..d17e2f1 100644 --- a/src/engine/movepicker/movepicker.hpp +++ b/src/engine/movepicker/movepicker.hpp @@ -2,6 +2,8 @@ #include +#include + class Board; class Move; @@ -16,7 +18,7 @@ class MovePicker int _max_depth; int _current_nodes; - int _current_depth{}; + int _current_depth; int _killer_moves[2][MAX_DEPTH]{}; int _history_moves[N_SIDES][N_PIECES][N_SQUARES]{}; @@ -55,7 +57,7 @@ class MovePicker * @param move * @return move score */ - int score(const Move &move) const; + int score(const Move &move); int search(int depth); int negamax(int alpha, int beta, int depth, const Board &board); @@ -65,6 +67,8 @@ class MovePicker void addToHistoryMoves(Move const &move); void addToPrincipalVariation(Move const &move); + void clearSearchCounters(); + public: explicit MovePicker(Board &board) : _board(board), _max_depth(6), _current_nodes(0), _move_more_than_key{*this} { @@ -74,7 +78,7 @@ class MovePicker void setMaxDepth(int depth); - void clearState(); + void clearTables(); /** * @brief Searches the current position with max_depth diff --git a/src/interfaces/uci/uci.cpp b/src/interfaces/uci/uci.cpp index 52038f0..53d0261 100644 --- a/src/interfaces/uci/uci.cpp +++ b/src/interfaces/uci/uci.cpp @@ -199,7 +199,7 @@ namespace uci public: void execute(std::vector &args, Board &board) { - int max_depth = 7; + int max_depth = 6; if (args.size() != 0 && args[0] == "depth") { @@ -229,7 +229,7 @@ namespace uci // TODO: Refactor AI class to inherit from Board ?? MovePicker ai = MovePicker(board); ai.setMaxDepth(max_depth); - ai.clearState(); + ai.clearTables(); MovePicker::SearchResult result; for (int depth = 1; depth <= ai.getMaxDepth(); depth++) From 1d5bab835e7bb9186897884b96f67c295eb611b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Silveira?= Date: Mon, 11 Jul 2022 20:17:11 +0100 Subject: [PATCH 2/3] added principal variation search (#31) --- src/engine/movepicker/movepicker.cpp | 40 +++++++++++++++++++++++++--- src/interfaces/uci/uci.cpp | 2 +- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/src/engine/movepicker/movepicker.cpp b/src/engine/movepicker/movepicker.cpp index 026b9fc..3866824 100644 --- a/src/engine/movepicker/movepicker.cpp +++ b/src/engine/movepicker/movepicker.cpp @@ -91,19 +91,24 @@ int MovePicker::negamax(int alpha, int beta, int depth, const Board &board) { _current_nodes++; + // Terminal Node if (board.getHalfMoveClock() == 100) { + // Draw return 0; } + // Forced Terminal Node if (depth == 0) { _pv_length[_current_depth] = _current_depth; return quiescence(alpha, beta, -1, board); } - Move best_move = Move(); + bool first_node = true; bool has_legal_moves = false; + + Move best_move = Move(); std::vector moves = movegen::generatePseudoLegalMoves(board); std::sort(moves.begin(), moves.end(), _move_more_than_key); for (const Move &move : moves) @@ -113,10 +118,34 @@ int MovePicker::negamax(int alpha, int beta, int depth, const Board &board) int king_sq = bitboard::bitScanForward(backup.getPieces(backup.getOpponent(), KING)); if (!backup.isSquareAttacked(king_sq, backup.getSideToMove())) { + int score; has_legal_moves = true; - _current_depth++; - int score = -negamax(-beta, -alpha, depth - 1, backup); - _current_depth--; + + if (first_node) + { + first_node = false; + + _current_depth++; + score = -negamax(-beta, -alpha, depth - 1, backup); + _current_depth--; + } + else + { + // Perform a Null Window Search + _current_depth++; + score = -negamax(-alpha - 1, -alpha, depth - 1, backup); + _current_depth--; + + // If this move failed to prove to be bad, + // re-search with normal bounds + if ((score > alpha) && (score < beta)) + { + _current_depth++; + score = -negamax(-beta, -alpha, depth - 1, backup); + _current_depth--; + } + } + if (score >= beta) { // Killer Move Heuristic @@ -141,14 +170,17 @@ int MovePicker::negamax(int alpha, int beta, int depth, const Board &board) } } + // Terminal Node if (!has_legal_moves) { + // Check Mate int king_sq = bitboard::bitScanForward(board.getPieces(board.getSideToMove(), KING)); if (board.isSquareAttacked(king_sq, board.getOpponent())) { return MIN_EVAL + _current_depth; } + // Stale Mate return 0; } diff --git a/src/interfaces/uci/uci.cpp b/src/interfaces/uci/uci.cpp index 53d0261..5ee13fd 100644 --- a/src/interfaces/uci/uci.cpp +++ b/src/interfaces/uci/uci.cpp @@ -199,7 +199,7 @@ namespace uci public: void execute(std::vector &args, Board &board) { - int max_depth = 6; + int max_depth = 7; if (args.size() != 0 && args[0] == "depth") { From 7dabd3ee31cf2c2b36126bf20b25b3f7d1a7976e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o?= Date: Tue, 12 Jul 2022 18:09:41 +0100 Subject: [PATCH 3/3] fixed uninitialized value for alpha --- src/engine/movepicker/movepicker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/movepicker/movepicker.cpp b/src/engine/movepicker/movepicker.cpp index 3866824..7019d55 100644 --- a/src/engine/movepicker/movepicker.cpp +++ b/src/engine/movepicker/movepicker.cpp @@ -303,7 +303,7 @@ MovePicker::SearchResult MovePicker::findBestMove() this->clearTables(); // Iterative Deepening - int alpha; + int alpha{}; for (int depth = 1; depth <= _max_depth; depth++) { this->clearSearchCounters();