--- /dev/null
+/*
+ Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+ Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+ Copyright (C) 2008 Marco Costalba
+
+ Stockfish is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Stockfish is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+////
+//// Includes
+////
+
+#include "bitboard.h"
+#include "direction.h"
+#include "endgame.h"
+#include "evaluate.h"
+#include "material.h"
+#include "mersenne.h"
+#include "misc.h"
+#include "movepick.h"
+#include "position.h"
+#include "search.h"
+#include "thread.h"
+#include "ucioption.h"
+
+
+/// Application class is in charge of initializing global resources
+/// at startup and cleanly releases them when program terminates.
+
+Application::Application() {
+
+ init_mersenne();
+ init_direction_table();
+ init_bitboards();
+ init_uci_options();
+ Position::init_zobrist();
+ Position::init_piece_square_tables();
+ MovePicker::init_phase_table();
+ init_eval(1);
+ init_bitbases();
+ init_threads();
+
+ // Make random number generation less deterministic, for book moves
+ for (int i = abs(get_system_time() % 10000); i > 0; i--)
+ genrand_int32();
+}
+
+Application::~Application() {
+
+ stop_threads();
+ quit_eval();
+}
+
+void Application::initialize() {
+
+ instance();
+}
+
+Application& Application::instance() {
+
+ static Application singleton;
+ return singleton;
+}
+
+void Application::exit_with_failure() {
+
+ exit(EXIT_FAILURE); // d'tor will be called automatically
+}
--- /dev/null
+/*
+ Stockfish, a UCI chess playing engine derived from Glaurung 2.1
+ Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
+ Copyright (C) 2008 Marco Costalba
+
+ Stockfish is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Stockfish is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#if !defined(APPLICATION_H_INCLUDED)
+#define APPLICATION_H_INCLUDED
+
+
+/// Singleton class used to housekeep memory and global resources
+/// so to be sure we always leave in a clean state.
+
+class Application {
+
+ Application();
+ Application(const Application&);
+
+public:
+ static void initialize();
+ static void exit_with_failure();
+
+ ~Application();
+
+private:
+ static Application& instance();
+
+ void init();
+ void deallocateAll();
+};
+
+#endif // !defined(APPLICATION_H_INCLUDED)
if (val < 4 || val > 1024)
{
std::cerr << "The hash table size must be between 4 and 1024" << std::endl;
- exit(EXIT_FAILURE);
+ Application::exit_with_failure();
}
csStr >> threads;
csVal >> val;
if (val < 1 || val > THREAD_MAX)
{
- std::cerr << "The number of threads must be between 1 and " << THREAD_MAX
- << std::endl;
- exit(EXIT_FAILURE);
+ std::cerr << "The number of threads must be between 1 and " << THREAD_MAX << std::endl;
+ Application::exit_with_failure();
}
set_option_value("Hash", ttSize);
set_option_value("Threads", threads);
std::ifstream fenFile(fileName.c_str());
if (!fenFile.is_open())
{
- std::cerr << "Unable to open positions file " << fileName
- << std::endl;
- exit(EXIT_FAILURE);
+ std::cerr << "Unable to open positions file " << fileName << std::endl;
+ Application::exit_with_failure();
}
std::string pos;
while (fenFile.good())
int dummy[2] = {0, 0};
Position pos(*it);
std::cout << "\nProcessing position " << cnt << '/' << positions.size() << std::endl << std::endl;
- think(pos, true, false, 0, dummy, dummy, 0, maxDepth, maxNodes, secsPerPos, moves);
+ if (!think(pos, true, false, 0, dummy, dummy, 0, maxDepth, maxNodes, secsPerPos, moves))
+ break;
totalNodes += nodes_searched();
}
std::cout << "\nProcessing time (ms) " << get_system_time() - startTime << std::endl
if (!good())
{
cerr << "Failed to open book file " << fileName << endl;
- exit(EXIT_FAILURE);
+ Application::exit_with_failure();
}
}
if (!good())
{
cerr << "Failed to read book entry at index " << idx << endl;
- exit(EXIT_FAILURE);
+ Application::exit_with_failure();
}
}
{
delete PawnTable[i];
delete MaterialTable[i];
+ PawnTable[i] = NULL;
+ MaterialTable[i] = NULL;
}
}
// To profile with callgrind uncomment following line
//#define USE_CALLGRIND
+
////
//// Includes
////
#include <iostream>
+#include <string>
#include "benchmark.h"
-#include "bitboard.h"
-#include "direction.h"
-#include "endgame.h"
-#include "evaluate.h"
-#include "material.h"
-#include "mersenne.h"
#include "misc.h"
-#include "movepick.h"
-#include "position.h"
-#include "search.h"
-#include "thread.h"
#include "uci.h"
-#include "ucioption.h"
#ifdef USE_CALLGRIND
#include <valgrind/callgrind.h>
#endif
-using std::string;
+using namespace std;
+
////
//// Functions
int main(int argc, char *argv[]) {
// Disable IO buffering
- std::cout.rdbuf()->pubsetbuf(NULL, 0);
- std::cin.rdbuf()->pubsetbuf(NULL, 0);
-
- // Initialization
- init_mersenne();
- init_direction_table();
- init_bitboards();
- init_uci_options();
- Position::init_zobrist();
- Position::init_piece_square_tables();
- MovePicker::init_phase_table();
- init_eval(1);
- init_bitbases();
- init_threads();
+ cout.rdbuf()->pubsetbuf(NULL, 0);
+ cin.rdbuf()->pubsetbuf(NULL, 0);
+
+ // Initialization through global resources manager
+ Application::initialize();
#ifdef USE_CALLGRIND
CALLGRIND_START_INSTRUMENTATION;
#endif
- // Make random number generation less deterministic, for book moves
- for (int i = abs(get_system_time() % 10000); i > 0; i--)
- genrand_int32();
-
- // Process command line arguments
- if (argc >= 2 && string(argv[1]) == "bench")
+ // Process command line arguments if any
+ if (argc > 1)
{
- if (argc < 4 || argc > 7)
+ if (string(argv[1]) != "bench" || argc < 4 || argc > 7)
+ cout << "Usage: stockfish bench <hash size> <threads> "
+ << "[time = 60s] [fen positions file = default] "
+ << "[time, depth or node limited = time]" << endl;
+ else
{
- std::cout << "Usage: stockfish bench <hash size> <threads> "
- << "[time = 60s] [fen positions file = default] "
- << "[time, depth or node limited = time]"
- << std::endl;
- exit(0);
+ string time = argc > 4 ? argv[4] : "60";
+ string fen = argc > 5 ? argv[5] : "default";
+ string lim = argc > 6 ? argv[6] : "time";
+ benchmark(string(argv[2]) + " " + string(argv[3]) + " " + time + " " + fen + " " + lim);
}
- string time = argc > 4 ? argv[4] : "60";
- string fen = argc > 5 ? argv[5] : "default";
- string lim = argc > 6 ? argv[6] : "time";
- benchmark(string(argv[2]) + " " + string(argv[3]) + " " + time + " " + fen + " " + lim);
return 0;
}
// Print copyright notice
- std::cout << engine_name() << ". Copyright (C) "
- << "2004-2008 Tord Romstad, Marco Costalba. "
- << std::endl;
+ cout << engine_name() << ". Copyright (C) "
+ << "2004-2008 Tord Romstad, Marco Costalba. " << endl;
// Enter UCI mode
uci_main_loop();
-
return 0;
}
{
std::cerr << "Failed to allocate " << (numOfEntries * sizeof(MaterialInfo))
<< " bytes for material hash table." << std::endl;
- exit(EXIT_FAILURE);
+ Application::exit_with_failure();
}
clear();
}
#include <fstream>
#include <string>
+#include "application.h"
////
//// Macros
extern int cpu_count();
extern int Bioskey();
+
////
//// Debug
////
{
std::cerr << "Failed to allocate " << (numOfEntries * sizeof(PawnInfo))
<< " bytes for pawn hash table." << std::endl;
- exit(EXIT_FAILURE);
+ Application::exit_with_failure();
}
clear();
}
////
/// think() is the external interface to Stockfish's search, and is called when
-/// the program receives the UCI 'go' command. It initializes various
-/// search-related global variables, and calls root_search()
+/// the program receives the UCI 'go' command. It initializes various
+/// search-related global variables, and calls root_search(). It returns false
+/// when a quit command is received during the search.
-void think(const Position &pos, bool infinite, bool ponder, int side_to_move,
+bool think(const Position &pos, bool infinite, bool ponder, int side_to_move,
int time[], int increment[], int movesToGo, int maxDepth,
int maxNodes, int maxTime, Move searchMoves[]) {
if (bookMove != MOVE_NONE)
{
std::cout << "bestmove " << bookMove << std::endl;
- return;
+ return true;
}
}
if (UseLogFile)
LogFile.close();
- if (Quit)
- {
- stop_threads();
- quit_eval();
- exit(0);
- }
Idle = true;
+ return !Quit;
}
AbortSearch = true;
PonderSearch = false;
Quit = true;
+ return;
}
else if(command == "stop")
{
// after which the bestmove and pondermove will be printed (in id_loop()).
void wait_for_stop_or_ponderhit() {
+
std::string command;
- while(true) {
- if(!std::getline(std::cin, command))
- command = "quit";
+ while (true)
+ {
+ if (!std::getline(std::cin, command))
+ command = "quit";
- if(command == "quit") {
- stop_threads();
- quit_eval();
- exit(0);
- }
- else if(command == "ponderhit" || command == "stop")
- break;
+ if (command == "quit")
+ {
+ Quit = true;
+ break;
+ }
+ else if(command == "ponderhit" || command == "stop")
+ break;
}
}
extern void init_threads();
extern void stop_threads();
-extern void think(const Position &pos, bool infinite, bool ponder, int side_to_move,
+extern bool think(const Position &pos, bool infinite, bool ponder, int side_to_move,
int time[], int increment[], int movesToGo, int maxDepth,
int maxNodes, int maxTime, Move searchMoves[]);
extern int64_t nodes_searched();
{
std::cerr << "Failed to allocate " << mbSize
<< " MB for transposition table." << std::endl;
- exit(EXIT_FAILURE);
+ Application::exit_with_failure();
}
clear();
}
Position RootPosition;
// Local functions
- void get_command();
- void handle_command(const std::string &command);
- void set_option(UCIInputParser &uip);
- void set_position(UCIInputParser &uip);
- void go(UCIInputParser &uip);
+ bool handle_command(const std::string& command);
+ void set_option(UCIInputParser& uip);
+ void set_position(UCIInputParser& uip);
+ bool go(UCIInputParser& uip);
}
//// Functions
////
-/// uci_main_loop() is the only global function in this file. It is
+/// uci_main_loop() is the only global function in this file. It is
/// called immediately after the program has finished initializing.
/// The program remains in this loop until it receives the "quit" UCI
-/// command.
+/// command. It waits for a command from the user, and passes this
+/// command to handle_command and also intercepts EOF from stdin,
+/// by translating EOF to the "quit" command. This ensures that Stockfish
+/// exits gracefully if the GUI dies unexpectedly.
void uci_main_loop() {
RootPosition.from_fen(StartPosition);
+ std::string command;
- while (1)
- get_command();
+ do {
+ // Wait for a command from stdin
+ if (!std::getline(std::cin, command))
+ command = "quit";
+
+ } while (handle_command(command));
}
namespace {
- // get_command() waits for a command from the user, and passes
- // this command to handle_command. get_command also intercepts
- // EOF from stdin, by translating EOF to the "quit" command. This
- // ensures that Stockfish exits gracefully if the GUI dies
- // unexpectedly.
-
- void get_command() {
-
- std::string command;
-
- if (!std::getline(std::cin, command))
- command = "quit";
-
- handle_command(command);
- }
-
-
// handle_command() takes a text string as input, uses a
// UCIInputParser object to parse this text string as a UCI command,
- // and calls the appropriate functions. In addition to the UCI
+ // and calls the appropriate functions. In addition to the UCI
// commands, the function also supports a few debug commands.
- void handle_command(const std::string &command) {
+ bool handle_command(const std::string& command) {
UCIInputParser uip(command);
std::string token;
uip >> token; // operator >> skips any whitespace
if (token == "quit")
- {
- stop_threads();
- quit_eval();
- exit(0);
- }
- else if (token == "uci")
+ return false;
+
+ if (token == "go")
+ return go(uip);
+
+ if (token == "uci")
{
std::cout << "id name " << engine_name() << std::endl
<< "id author Tord Romstad, Marco Costalba"
set_position(uip);
else if (token == "setoption")
set_option(uip);
- else if (token == "go")
- go(uip);
// The remaining commands are for debugging purposes only.
// Perhaps they should be removed later in order to reduce the
std::cout << token << std::endl;
}
}
+ return true;
}
// ("position"), and is ready to read the second token ("startpos"
// or "fen", if the input is well-formed).
- void set_position(UCIInputParser &uip) {
+ void set_position(UCIInputParser& uip) {
std::string token;
// ("setoption"), and is ready to read the second token ("name", if
// the input is well-formed).
- void set_option(UCIInputParser &uip) {
+ void set_option(UCIInputParser& uip) {
std::string token, name;
// go() is called when Stockfish receives the "go" UCI command. The
- // input parameter is a UCIInputParser. It is assumed that this
+ // input parameter is a UCIInputParser. It is assumed that this
// parser has consumed the first token of the UCI command ("go"),
- // and is ready to read the second token. The function sets the
+ // and is ready to read the second token. The function sets the
// thinking time and other parameters from the input string, and
// calls think() (defined in search.cpp) with the appropriate
- // parameters.
+ // parameters. Returns false if a quit command is received while
+ // thinking, returns true otherwise.
- void go(UCIInputParser &uip) {
+ bool go(UCIInputParser& uip) {
std::string token;
assert(RootPosition.is_ok());
- think(RootPosition, infinite, ponder, RootPosition.side_to_move(), time,
- inc, movesToGo, depth, nodes, moveTime, searchMoves);
+ return think(RootPosition, infinite, ponder, RootPosition.side_to_move(), time,
+ inc, movesToGo, depth, nodes, moveTime, searchMoves);
}
}