2 Glaurung, a UCI chess playing engine.
3 Copyright (C) 2004-2008 Tord Romstad
5 Glaurung is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 Glaurung is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
36 #include "ucioption.h"
40 //// Local definitions:
45 // UCIInputParser is a class for parsing UCI input. The class is
46 // very simple, and basically just consist of a constant input
47 // string and a current location in the string. There are methods
48 // for checking if we are at the end of the line, for getting the
49 // next token (defined as any whitespace-delimited sequence of
50 // characters), and for getting the rest of the line as a single
53 class UCIInputParser {
56 UCIInputParser(const std::string &line);
57 std::string get_next_token();
58 std::string get_rest_of_line();
59 bool at_end_of_line();
62 const std::string &inputLine;
63 int length, currentIndex;
65 void skip_whitespace();
70 // The root position. This is set up when the user (or in practice, the GUI)
71 // sends the "position" UCI command. The root position is sent to the think()
72 // function when the program receives the "go" command.
73 Position RootPosition;
76 void wait_for_command();
77 void handle_command(const std::string &command);
78 void set_option(UCIInputParser &uip);
79 void set_position(UCIInputParser &uip);
80 void go(UCIInputParser &uip);
88 /// uci_main_loop() is the only global function in this file. It is
89 /// called immediately after the program has finished initializing.
90 /// The program remains in this loop until it receives the "quit" UCI
93 void uci_main_loop() {
94 RootPosition.from_fen(StartPosition);
95 while(1) wait_for_command();
106 /// Implementation of the UCIInputParser class.
109 // Constructor for the UCIInputParser class. The constructor takes a
110 // text string containing a single UCI command as input.
112 UCIInputParser::UCIInputParser(const std::string &line) : inputLine(line) {
113 this->currentIndex = 0;
114 this->length = line.length();
118 // UCIInputParser::skip_whitspace() skips any number of whitespace
119 // characters from the current location in an input string.
121 void UCIInputParser::skip_whitespace() {
122 while(isspace(std::char_traits<char>::to_int_type(this->inputLine[this->currentIndex])))
123 this->currentIndex++;
127 // UCIInputParser::get_next_token() gets the next token in an UCI
128 // command. A 'token' in an UCI command is simply any
129 // whitespace-delimited sequence of characters.
131 std::string UCIInputParser::get_next_token() {
134 this->skip_whitespace();
135 for(i = j = this->currentIndex;
136 j < this->length && !isspace(this->inputLine[j]);
138 this->currentIndex = j;
139 this->skip_whitespace();
141 std::string str = this->inputLine.substr(i, j - i);
147 // UCIInputParser::get_rest_of_line() returns the rest of the input
148 // line (from the current location) as a single string.
150 std::string UCIInputParser::get_rest_of_line() {
151 this->skip_whitespace();
152 return this->inputLine.substr(this->currentIndex, this->length);
156 // UCIInputParser::at_end_of_line() tests whether we have reached the
157 // end of the input string, i.e. if any more input remains to be
160 bool UCIInputParser::at_end_of_line() {
161 return this->currentIndex == this->length;
170 // wait_for_command() waits for a command from the user, and passes
171 // this command to handle_command. wait_for_command also intercepts
172 // EOF from stdin, by translating EOF to the "quit" command. This
173 // ensures that Glaurung exits gracefully if the GUI dies
176 void wait_for_command() {
178 if(!std::getline(std::cin, command)) command = "quit";
179 handle_command(command);
183 // handle_command() takes a text string as input, uses a
184 // UCIInputParser object to parse this text string as a UCI command,
185 // and calls the appropriate functions. In addition to the UCI
186 // commands, the function also supports a few debug commands.
188 void handle_command(const std::string &command) {
189 UCIInputParser uip(command);
190 std::string s = uip.get_next_token();
198 else if(s == "uci") {
199 std::cout << "id name " << engine_name() << std::endl;
200 std::cout << "id author Tord Romstad" << std::endl;
202 std::cout << "uciok" << std::endl;
204 else if(s == "ucinewgame") {
206 Position::init_piece_square_tables();
207 RootPosition.from_fen(StartPosition);
209 else if(s == "isready")
210 std::cout << "readyok" << std::endl;
211 else if(s == "position")
213 else if(s == "setoption")
218 // The remaining commands are for debugging purposes only.
219 // Perhaps they should be removed later in order to reduce the
220 // size of the program binary.
222 RootPosition.print();
223 else if(s == "flip") {
224 Position p(RootPosition);
225 RootPosition.flipped_copy(p);
227 else if(s == "eval") {
229 std::cout << "Incremental mg: " << RootPosition.mg_value()
231 std::cout << "Incremental eg: " << RootPosition.eg_value()
233 std::cout << "Full eval: "
234 << evaluate(RootPosition, ei, 0)
237 else if(s == "key") {
238 std::cout << "key: " << RootPosition.get_key()
239 << " material key: " << RootPosition.get_material_key()
240 << " pawn key: " << RootPosition.get_pawn_key()
244 std::cout << "Unknown command: " << command << std::endl;
245 while(!uip.at_end_of_line()) {
246 std::cout << uip.get_next_token() << std::endl;
252 // set_position() is called when Glaurung receives the "position" UCI
253 // command. The input parameter is a UCIInputParser. It is assumed
254 // that this parser has consumed the first token of the UCI command
255 // ("position"), and is ready to read the second token ("startpos"
256 // or "fen", if the input is well-formed).
258 void set_position(UCIInputParser &uip) {
261 token = uip.get_next_token();
262 if(token == "startpos")
263 RootPosition.from_fen(StartPosition);
264 else if(token == "fen") {
266 while(token != "moves" && !uip.at_end_of_line()) {
267 token = uip.get_next_token();
271 RootPosition.from_fen(fen);
274 if(!uip.at_end_of_line()) {
276 token = uip.get_next_token();
277 if(token == "moves") {
280 while(!uip.at_end_of_line()) {
281 token = uip.get_next_token();
282 move = move_from_string(RootPosition, token);
283 RootPosition.do_move(move, u);
284 if(RootPosition.rule_50_counter() == 0)
285 RootPosition.reset_game_ply();
292 // set_option() is called when Glaurung receives the "setoption" UCI
293 // command. The input parameter is a UCIInputParser. It is assumed
294 // that this parser has consumed the first token of the UCI command
295 // ("setoption"), and is ready to read the second token ("name", if
296 // the input is well-formed).
298 void set_option(UCIInputParser &uip) {
300 if(!uip.at_end_of_line()) {
301 token = uip.get_next_token();
302 if(token == "name" && !uip.at_end_of_line()) {
303 std::string name = uip.get_next_token();
304 std::string nextToken;
305 while(!uip.at_end_of_line()
306 && (nextToken = uip.get_next_token()) != "value")
307 name += (" " + nextToken);
308 if(nextToken == "value")
309 set_option_value(name, uip.get_rest_of_line());
317 // go() is called when Glaurung receives the "go" UCI command. The
318 // input parameter is a UCIInputParser. It is assumed that this
319 // parser has consumed the first token of the UCI command ("go"),
320 // and is ready to read the second token. The function sets the
321 // thinking time and other parameters from the input string, and
322 // calls think() (defined in search.cpp) with the appropriate
325 void go(UCIInputParser &uip) {
327 int time[2] = {0, 0}, inc[2] = {0, 0}, movesToGo = 0, depth = 0, nodes = 0;
329 bool infinite = false, ponder = false;
330 Move searchMoves[500];
332 searchMoves[0] = MOVE_NONE;
334 while(!uip.at_end_of_line()) {
335 token = uip.get_next_token();
337 if(token == "infinite")
339 else if(token == "ponder")
341 else if(token == "wtime") {
342 if(!uip.at_end_of_line())
343 time[0] = atoi(uip.get_next_token().c_str());
345 else if(token == "btime") {
346 if(!uip.at_end_of_line())
347 time[1] = atoi(uip.get_next_token().c_str());
349 else if(token == "winc") {
350 if(!uip.at_end_of_line())
351 inc[0] = atoi(uip.get_next_token().c_str());
353 else if(token == "binc") {
354 if(!uip.at_end_of_line())
355 inc[1] = atoi(uip.get_next_token().c_str());
357 else if(token == "movestogo") {
358 if(!uip.at_end_of_line())
359 movesToGo = atoi(uip.get_next_token().c_str());
361 else if(token == "depth") {
362 if(!uip.at_end_of_line())
363 depth = atoi(uip.get_next_token().c_str());
365 else if(token == "nodes") {
366 if(!uip.at_end_of_line())
367 nodes = atoi(uip.get_next_token().c_str());
369 else if(token == "movetime") {
370 if(!uip.at_end_of_line())
371 moveTime = atoi(uip.get_next_token().c_str());
373 else if(token == "searchmoves" && !uip.at_end_of_line()) {
375 while(!uip.at_end_of_line()) {
376 token = uip.get_next_token();
377 searchMoves[numOfMoves++] = move_from_string(RootPosition, token);
379 searchMoves[numOfMoves] = MOVE_NONE;
384 infinite = true; // HACK
386 think(RootPosition, infinite, ponder, time[RootPosition.side_to_move()],
387 inc[RootPosition.side_to_move()], movesToGo, depth, nodes, moveTime,