Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleanup search #77

Merged
merged 2 commits into from
Aug 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions engine/src/board_code.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,7 @@ namespace wisdom

auto operator<< (std::ostream& os, const BoardCode& code) -> std::ostream&
{
os << "{ bits: ";
for (const auto& bits : code.my_pieces)
os << bits;
os << ", metadata: " << code.my_metadata << " }";
os << code.asString();
return os;
}

Expand Down
80 changes: 38 additions & 42 deletions engine/src/search.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,12 @@ namespace wisdom

void iterate (Color side, int depth);

void search (const Board& parent_board, Color side, int depth, int alpha, int beta);
// Search for the best move, and return the best score.
int search (const Board& parent_board, Color side, int depth,
int alpha, int beta);

[[nodiscard]] auto synthesizeResult() const -> SearchResult;
// Get the best result the search found.
[[nodiscard]] auto getBestResult() const -> SearchResult;

[[nodiscard]] auto moveTimer() const -> not_null<const MoveTimer*>
{
Expand All @@ -42,16 +45,12 @@ namespace wisdom
Board my_original_board;
History my_history;
not_null<observer_ptr<const Logger>> my_output;
SearchResult my_current_result {};
MoveGenerator my_generator {};
MoveTimer my_timer;

int my_total_depth;
int my_search_depth {};

optional<Move> my_best_move = nullopt;
int my_best_depth = -1;
int my_best_score = -1;
bool my_timed_out = false;

int my_nodes_visited = 0;
int my_alpha_beta_cutoffs = 0;
int my_total_nodes_visited = 0;
Expand All @@ -71,7 +70,7 @@ namespace wisdom
IterativeSearch::iterativelyDeepen (Color side)
{
impl->iterativelyDeepen (side);
return impl->synthesizeResult();
return impl->getBestResult();
}

auto IterativeSearch::isCancelled() -> bool
Expand All @@ -90,19 +89,21 @@ namespace wisdom
return current_color == searching_color ? Min_Draw_Score : 0;
}

void IterativeSearchImpl::search (const Board& parent_board, // NOLINT(misc-no-recursion)
Color side, int depth, int alpha, int beta)
int IterativeSearchImpl::search (const Board& parent_board, // NOLINT(misc-no-recursion)
Color side, int depth, int alpha, int beta)
{
std::optional<Move> best_move {};
int best_score = -Initial_Alpha;

auto moves = my_generator.generateAllPotentialMoves (parent_board, side);
for (auto move : moves)
{
int score;

if (my_timer.isTriggered())
{
my_timed_out = true;
return;
my_current_result.timed_out = true;
return -Initial_Alpha;
}

Board child_board = parent_board.withMove (side, move);
Expand All @@ -118,30 +119,27 @@ namespace wisdom
{
if (isDrawingMove (child_board, side, move, my_history))
{
my_best_score = drawingScore (my_searching_color, side);
score = drawingScore (my_searching_color, side);
}
else
{
my_best_score = evaluate (child_board, side,
my_search_depth - depth, my_generator);
score = evaluate (child_board, side,
my_search_depth - depth, my_generator);
}
}
else
{
// Don't recurse into a big search if this move is a draw.
if (my_search_depth == depth && isDrawingMove (child_board, side, move, my_history))
{
my_best_score = drawingScore (my_searching_color, side);
score = drawingScore (my_searching_color, side);
}
else
{
search (child_board, colorInvert (side), depth-1, -beta, -alpha);
my_best_score *= -1;
score = -1 * search (child_board, colorInvert (side), depth-1, -beta, -alpha);
}
}

int score = my_best_score;

if (score > best_score)
{
best_score = score;
Expand All @@ -153,8 +151,8 @@ namespace wisdom

my_history.removeLastTentativePosition();

if (my_timed_out)
return;
if (my_current_result.timed_out)
return -Initial_Alpha;

if (alpha >= beta)
{
Expand All @@ -163,17 +161,17 @@ namespace wisdom
}
}

auto result = SearchResult { best_move, best_score,
my_search_depth - depth, false };

my_best_move = result.move;
if (!my_best_move.has_value())
my_current_result.depth = my_search_depth - depth;
if (!best_move.has_value())
{
// if there are no legal moves, then the current player is in a stalemate or checkmate position.
result.score = evaluateWithoutLegalMoves (parent_board, side, result.depth);
// if there are no legal moves, then the current player is in a
// stalemate or checkmate position.
best_score = evaluateWithoutLegalMoves (parent_board, side,
my_current_result.depth);
}
my_best_score = result.score;
my_best_depth = result.depth;
my_current_result.move = best_move;
my_current_result.score = best_score;
return best_score;
}

static void calc_time (const Logger& output, int nodes, system_clock_t start, system_clock_t end)
Expand All @@ -188,7 +186,7 @@ namespace wisdom

void IterativeSearchImpl::iterativelyDeepen (Color side)
{
SearchResult best_result = SearchResult::from_initial();
SearchResult best_result {};
my_searching_color = side;

try
Expand All @@ -203,10 +201,10 @@ namespace wisdom
my_output->info (ostr.str());

iterate (side, depth);
if (my_timed_out)
if (my_current_result.timed_out)
break;

auto next_result = synthesizeResult();
auto next_result = getBestResult();
if (next_result.move.has_value())
{
best_result = next_result;
Expand All @@ -215,9 +213,7 @@ namespace wisdom
}
}

my_best_score = best_result.score;
my_best_move = best_result.move;
my_best_depth = best_result.depth;
my_current_result = best_result;
return;
}
catch (const Error &e)
Expand All @@ -228,10 +224,9 @@ namespace wisdom
}
}

[[nodiscard]] auto IterativeSearchImpl::synthesizeResult() const -> SearchResult
[[nodiscard]] auto IterativeSearchImpl::getBestResult() const -> SearchResult
{
return SearchResult { my_best_move,
my_best_score, my_best_depth, my_timed_out };
return my_current_result;
}

void IterativeSearchImpl::iterate (Color side, int depth)
Expand All @@ -246,11 +241,12 @@ namespace wisdom
auto start = std::chrono::system_clock::now();

my_search_depth = depth;
my_current_result = SearchResult {};
search (my_original_board, side, depth, -Initial_Alpha, Initial_Alpha);

auto end = std::chrono::system_clock::now();

auto result = synthesizeResult();
auto result = getBestResult();

calc_time (*my_output, my_nodes_visited, start, end);

Expand Down
14 changes: 4 additions & 10 deletions engine/src/search.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,10 @@ namespace wisdom

struct SearchResult
{
optional<Move> move;
int score;
int depth;
bool timed_out;

static SearchResult from_initial() noexcept
{
SearchResult result { nullopt, -Initial_Alpha, 0, false };
return result;
}
int score = -Initial_Alpha;
int depth { 0 };
optional<Move> move { nullopt };
bool timed_out { false };
};

class IterativeSearch
Expand Down
35 changes: 35 additions & 0 deletions engine/test/board_code_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include <algorithm>
#include <iostream>
#include <sstream>

#include "board_code.hpp"
#include "coord.hpp"
Expand Down Expand Up @@ -141,6 +142,40 @@ TEST_CASE( "board code")
}
}

TEST_CASE( "Board code can be converted" )
{
SUBCASE( "to a string" )
{
std::stringstream stream;
BoardCode code = BoardCode::fromEmptyBoard();

code.addPiece(
coordParse("h1"),
ColoredPiece::make(Color::White, Piece::King)
);

auto result = code.asString().substr(0, 4);

CHECK( result == "0110" );
}

SUBCASE( "to an ostream" )
{
std::stringstream stream;
BoardCode code = BoardCode::fromEmptyBoard();

code.addPiece(
coordParse("h1"),
ColoredPiece::make(Color::White, Piece::King)
);

stream << code;
auto result = stream.str().substr(0, 4);

CHECK( result == "0110" );
}
}

TEST_CASE( "Board code stores metadata" )
{
SUBCASE( "Board code stores en passant state for Black" )
Expand Down