Skip to content

Commit

Permalink
Add a StepVerbose override to the UCIBot
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 642319505
Change-Id: I16c1ea4d79a3ccba94716a08381a5d745e3176a6
  • Loading branch information
calewis authored and lanctot committed Jul 15, 2024
1 parent 7959c89 commit 5c57b86
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 11 deletions.
5 changes: 5 additions & 0 deletions open_spiel/bots/uci/random_uci_bot.cc
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,15 @@ void RandomUciBot() {
absl::StartsWith(line, "go depth") ||
absl::StartsWith(line, "go nodes") ||
absl::StartsWith(line, "go mate")) {
std::cout << "info string Random uci bot uci info statistics may not be "
"accurate.\n";
std::vector<Action> legal_actions = state->LegalActions();
int index = absl::Uniform<int>(rng, 0, legal_actions.size());
Action action = legal_actions[index];
chess::Move move = ActionToMove(action, chess_state->Board());
std::cout << "info depth 1 seldepth 1 multipv 1 nodes 1 nps 1000 "
"hashfull 0 tbhits 0 time 1 pv "
<< move.ToLAN() << "\n";
std::cout << "bestmove " << move.ToLAN() << std::endl;
} else if (line == "quit") {
return;
Expand Down
29 changes: 21 additions & 8 deletions open_spiel/bots/uci/uci_bot.cc
Original file line number Diff line number Diff line change
Expand Up @@ -91,20 +91,23 @@ UCIBot::~UCIBot() {
close(output_fd_);
}

Action UCIBot::Step(const State& state) {
Action UCIBot::Step(const State& state) { return StepVerbose(state).first; }

std::pair<Action, std::string> UCIBot::StepVerbose(const State& state) {
std::string move_str;
std::string info_str; // Contains the last info string from the bot.
auto chess_state = down_cast<const chess::ChessState&>(state);
if (ponder_ && ponder_move_) {
if (!was_ponder_hit_) {
Stop();
Position(chess_state.Board().ToFEN());
tie(move_str, ponder_move_) = Go();
tie(move_str, ponder_move_) = Go(&info_str);
} else {
tie(move_str, ponder_move_) = ReadBestMove();
tie(move_str, ponder_move_) = ReadBestMove(&info_str);
}
} else {
Position(chess_state.Board().ToFEN());
tie(move_str, ponder_move_) = Go();
tie(move_str, ponder_move_) = Go(&info_str);
}
was_ponder_hit_ = false;
auto move = chess_state.Board().ParseLANMove(move_str);
Expand All @@ -118,7 +121,7 @@ Action UCIBot::Step(const State& state) {
}

Action action = chess::MoveToAction(*move);
return action;
return {action, info_str};
}

void UCIBot::Restart() {
Expand Down Expand Up @@ -239,9 +242,10 @@ void UCIBot::Position(const std::string& fen,
Write(msg);
}

std::pair<std::string, absl::optional<std::string>> UCIBot::Go() {
std::pair<std::string, absl::optional<std::string>> UCIBot::Go(
absl::optional<std::string*> info_string) {
Write("go " + search_limit_string_);
return ReadBestMove();
return ReadBestMove(info_string);
}

void UCIBot::GoPonder() { Write("go ponder " + search_limit_string_); }
Expand All @@ -255,10 +259,19 @@ std::pair<std::string, absl::optional<std::string>> UCIBot::Stop() {

void UCIBot::Quit() { Write("quit"); }

std::pair<std::string, absl::optional<std::string>> UCIBot::ReadBestMove() {
std::pair<std::string, absl::optional<std::string>> UCIBot::ReadBestMove(
absl::optional<std::string*> info_string) {
while (true) {
// istringstream can't use a string_view so we need to copy to a string.
std::string response = ReadLine();
// Save the most recent info string if requested. Specifying that the string
// contains the number of nodes makes sure that we don't save strings of the
// form "info depth 30 currmove c2c1 currmovenumber 22", we want the ones
// with metadata about the search.
if (info_string.has_value() && absl::StartsWith(response, "info") &&
absl::StrContains(response, "nodes")) {
*info_string.value() = response;
}
std::istringstream response_line(response);
std::string token;
std::string move_str;
Expand Down
9 changes: 7 additions & 2 deletions open_spiel/bots/uci/uci_bot.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ class UCIBot : public Bot {
~UCIBot() override;

Action Step(const State& state) override;

std::pair<Action, std::string> StepVerbose(const State& state) override;

void Restart() override;
void RestartAt(const State& state) override;

Expand All @@ -72,12 +75,14 @@ class UCIBot : public Bot {
void SetOption(const std::string& name, const std::string& value);
void UciNewGame();
void IsReady();
std::pair<std::string, absl::optional<std::string>> Go();
std::pair<std::string, absl::optional<std::string>> Go(
absl::optional<std::string*> info_string = absl::nullopt);
void GoPonder();
void PonderHit();
std::pair<std::string, absl::optional<std::string>> Stop();
void Quit();
std::pair<std::string, absl::optional<std::string>> ReadBestMove();
std::pair<std::string, absl::optional<std::string>> ReadBestMove(
absl::optional<std::string*> info_string = absl::nullopt);

pid_t pid_ = -1;
int output_fd_ = -1;
Expand Down
17 changes: 16 additions & 1 deletion open_spiel/bots/uci/uci_bot_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@

#include "open_spiel/abseil-cpp/absl/flags/flag.h"
#include "open_spiel/abseil-cpp/absl/flags/parse.h"
#include "open_spiel/abseil-cpp/absl/strings/match.h"
#include "open_spiel/algorithms/evaluate_bots.h"
#include "open_spiel/spiel.h"
#include "open_spiel/spiel_bots.h"
#include "open_spiel/spiel_utils.h"
#include "open_spiel/utils/init.h"

ABSL_FLAG(std::string, binary, "random_uci_bot", "Name of the binary to run.");
Expand All @@ -43,20 +45,33 @@ void RandomUciBotTest() {
/*ponder*/ false, /*options*/ options);
auto bot2 = std::make_unique<UCIBot>(binary, /*move_time*/ 10,
/*ponder*/ false, /*options*/ options);
std::vector<Bot*> bots = {bot1.get(), bot2.get()};
std::vector<Bot *> bots = {bot1.get(), bot2.get()};
for (int i = 0; i < kNumGames; ++i) {
std::unique_ptr<State> state = game->NewInitialState();
EvaluateBots(state.get(), bots, kSeed);
std::cout << "Game over: " << state->HistoryString() << std::endl;
}
}

void CheckVerboseOutput() {
std::string binary = absl::GetFlag(FLAGS_binary);
std::shared_ptr<const Game> game = LoadGame("chess");
auto bot = UCIBot(binary, /*move_time*/ 10,
/*ponder*/ false, /*options*/ {});
std::unique_ptr<State> state = game->NewInitialState();
auto [action, info] = bot.StepVerbose(*state);

SPIEL_CHECK_TRUE(absl::StrContains(info, "info"));
std::cout << "Verbose output: " << info << std::endl;
}

} // namespace
} // namespace uci
} // namespace open_spiel

int main(int argc, char **argv) {
open_spiel::Init("", &argc, &argv, false);
absl::ParseCommandLine(argc, argv);
open_spiel::uci::CheckVerboseOutput();
open_spiel::uci::RandomUciBotTest();
}

0 comments on commit 5c57b86

Please sign in to comment.