]> git.sesse.net Git - stockfish/blob - src/uci.cpp
a3b4d8c0ed72ef2efe14f1f45698a94f00020557
[stockfish] / src / uci.cpp
1 /*
2   Glaurung, a UCI chess playing engine.
3   Copyright (C) 2004-2008 Tord Romstad
4
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.
9   
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.
14   
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/>.
17 */
18
19
20 ////
21 //// Includes
22 ////
23
24 #include <iostream>
25 #include <string>
26
27 #include "book.h"
28 #include "evaluate.h"
29 #include "misc.h"
30 #include "move.h"
31 #include "movegen.h"
32 #include "position.h"
33 #include "san.h"
34 #include "search.h"
35 #include "uci.h"
36 #include "ucioption.h"
37
38
39 ////
40 //// Local definitions:
41 ////
42
43 namespace {
44
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
51   // string.
52
53   class UCIInputParser {
54
55   public:
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();
60
61   private:
62     const std::string &inputLine;
63     int length, currentIndex;
64
65     void skip_whitespace();
66
67   };
68
69
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;
74
75   // Local functions
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);
81 }
82
83
84 ////
85 //// Functions
86 ////
87
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
91 /// command.
92
93 void uci_main_loop() {
94   RootPosition.from_fen(StartPosition);
95   while(1) wait_for_command();
96 }
97
98
99 ////
100 //// Local functions
101 ////
102
103 namespace {
104
105   ///
106   /// Implementation of the UCIInputParser class.
107   ///
108
109   // Constructor for the UCIInputParser class.  The constructor takes a 
110   // text string containing a single UCI command as input.
111
112   UCIInputParser::UCIInputParser(const std::string &line) : inputLine(line) {
113     this->currentIndex = 0;
114     this->length = line.length();
115   }
116
117
118   // UCIInputParser::skip_whitspace() skips any number of whitespace
119   // characters from the current location in an input string.
120
121   void UCIInputParser::skip_whitespace() {
122     while(isspace(std::char_traits<char>::to_int_type(this->inputLine[this->currentIndex])))
123       this->currentIndex++;
124   }
125
126
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.
130
131   std::string UCIInputParser::get_next_token() {
132     int i, j;
133
134     this->skip_whitespace();
135     for(i = j = this->currentIndex; 
136         j < this->length && !isspace(this->inputLine[j]); 
137         j++);
138     this->currentIndex = j;
139     this->skip_whitespace();
140
141     std::string str = this->inputLine.substr(i, j - i);
142
143     return str;
144   }
145
146
147   // UCIInputParser::get_rest_of_line() returns the rest of the input
148   // line (from the current location) as a single string.
149
150   std::string UCIInputParser::get_rest_of_line() {
151     this->skip_whitespace();
152     return this->inputLine.substr(this->currentIndex, this->length);
153   }
154
155
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
158   // parsed.
159
160   bool UCIInputParser::at_end_of_line() {
161     return this->currentIndex == this->length;
162   }
163
164
165   /// 
166   /// Other functions
167   ///
168
169
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
174   // unexpectedly.
175
176   void wait_for_command() {
177     std::string command;
178     if(!std::getline(std::cin, command)) command = "quit";
179     handle_command(command);
180   }
181
182
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.
187   
188   void handle_command(const std::string &command) {
189     UCIInputParser uip(command);
190     std::string s = uip.get_next_token();
191
192     if(s == "quit") {
193       OpeningBook.close();
194       stop_threads();
195       quit_eval();
196       exit(0);
197     }
198     else if(s == "uci") {
199       std::cout << "id name " << engine_name() << std::endl;
200       std::cout << "id author Tord Romstad" << std::endl;
201       print_uci_options();
202       std::cout << "uciok" << std::endl;
203     }
204     else if(s == "ucinewgame") {
205       TT.clear();
206       Position::init_piece_square_tables();
207       RootPosition.from_fen(StartPosition);
208     }
209     else if(s == "isready")
210       std::cout << "readyok" << std::endl;
211     else if(s == "position")
212       set_position(uip);
213     else if(s == "setoption")
214       set_option(uip);
215     else if(s == "go")
216       go(uip);
217
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.
221     else if(s == "d")
222       RootPosition.print();
223     else if(s == "flip") {
224       Position p(RootPosition);
225       RootPosition.flipped_copy(p);
226     }
227     else if(s == "eval") {
228       EvalInfo ei;
229       std::cout << "Incremental mg: " << RootPosition.mg_value()
230                 << std::endl;
231       std::cout << "Incremental eg: " << RootPosition.eg_value()
232                 << std::endl;
233       std::cout << "Full eval: "
234                 << evaluate(RootPosition, ei, 0)
235                 << std::endl;
236     }
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()
241                 << std::endl;
242     }
243     else {
244       std::cout << "Unknown command: " << command << std::endl;
245       while(!uip.at_end_of_line()) {
246         std::cout << uip.get_next_token() << std::endl;
247       }
248     }
249   }
250
251
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).
257
258   void set_position(UCIInputParser &uip) {
259     std::string token;
260
261     token = uip.get_next_token();
262     if(token == "startpos")
263       RootPosition.from_fen(StartPosition);
264     else if(token == "fen") {
265       std::string fen;
266       while(token != "moves" && !uip.at_end_of_line()) {
267         token = uip.get_next_token();
268         fen += token;
269         fen += ' ';
270       }
271       RootPosition.from_fen(fen);
272     }
273
274     if(!uip.at_end_of_line()) {
275       if(token != "moves")
276         token = uip.get_next_token();
277       if(token == "moves") {
278         Move move;
279         UndoInfo u;
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();
286         }
287       }
288     }
289   }
290
291
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).
297
298   void set_option(UCIInputParser &uip) {
299     std::string token;
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());
310         else
311           push_button(name);
312       }
313     }
314   }
315
316
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
323   // parameters.
324
325   void go(UCIInputParser &uip) {
326     std::string token;
327     int time[2] = {0, 0}, inc[2] = {0, 0}, movesToGo = 0, depth = 0, nodes = 0;
328     int moveTime = 0;
329     bool infinite = false, ponder = false;
330     Move searchMoves[500];
331
332     searchMoves[0] = MOVE_NONE;
333
334     while(!uip.at_end_of_line()) {
335       token = uip.get_next_token();
336
337       if(token == "infinite")
338         infinite = true;
339       else if(token == "ponder")
340         ponder = true;
341       else if(token == "wtime") {
342         if(!uip.at_end_of_line())
343           time[0] = atoi(uip.get_next_token().c_str());
344       }
345       else if(token == "btime") {
346         if(!uip.at_end_of_line())
347           time[1] = atoi(uip.get_next_token().c_str());
348       }
349       else if(token == "winc") {
350         if(!uip.at_end_of_line())
351           inc[0] = atoi(uip.get_next_token().c_str());
352       }
353       else if(token == "binc") {
354         if(!uip.at_end_of_line())
355           inc[1] = atoi(uip.get_next_token().c_str());
356       }
357       else if(token == "movestogo") {
358         if(!uip.at_end_of_line())
359           movesToGo = atoi(uip.get_next_token().c_str());
360       }
361       else if(token == "depth") {
362         if(!uip.at_end_of_line())
363           depth = atoi(uip.get_next_token().c_str());
364       }
365       else if(token == "nodes") {
366         if(!uip.at_end_of_line())
367           nodes = atoi(uip.get_next_token().c_str());
368       }
369       else if(token == "movetime") {
370         if(!uip.at_end_of_line())
371           moveTime = atoi(uip.get_next_token().c_str());
372       }
373       else if(token == "searchmoves" && !uip.at_end_of_line()) {
374         int numOfMoves = 0;
375         while(!uip.at_end_of_line()) {
376           token = uip.get_next_token();
377           searchMoves[numOfMoves++] = move_from_string(RootPosition, token);
378         }
379         searchMoves[numOfMoves] = MOVE_NONE;
380       }
381     }
382
383     if(moveTime)
384       infinite = true;  // HACK
385
386     think(RootPosition, infinite, ponder, time[RootPosition.side_to_move()],
387           inc[RootPosition.side_to_move()], movesToGo, depth, nodes, moveTime,
388           searchMoves);
389   }
390   
391 }