]> git.sesse.net Git - stockfish/blob - src/uci.cpp
Be sure book file is closed before we leave
[stockfish] / src / uci.cpp
1 /*
2   Stockfish, a UCI chess playing engine derived from Glaurung 2.1
3   Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
4   Copyright (C) 2008 Marco Costalba
5
6   Stockfish is free software: you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation, either version 3 of the License, or
9   (at your option) any later version.
10
11   Stockfish is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20
21 ////
22 //// Includes
23 ////
24
25 #include <cassert>
26 #include <iostream>
27 #include <sstream>
28 #include <string>
29
30 #include "book.h"
31 #include "evaluate.h"
32 #include "misc.h"
33 #include "move.h"
34 #include "movegen.h"
35 #include "position.h"
36 #include "san.h"
37 #include "search.h"
38 #include "uci.h"
39 #include "ucioption.h"
40
41
42 ////
43 //// Local definitions:
44 ////
45
46 namespace {
47
48   // UCIInputParser is a class for parsing UCI input.  The class
49   // is actually a string stream built on a given input string.
50
51   typedef std::istringstream UCIInputParser;
52
53   // The root position.  This is set up when the user (or in practice, the GUI)
54   // sends the "position" UCI command.  The root position is sent to the think()
55   // function when the program receives the "go" command.
56   Position RootPosition;
57
58   // Local functions
59   void get_command();
60   void handle_command(const std::string &command);
61   void set_option(UCIInputParser &uip);
62   void set_position(UCIInputParser &uip);
63   void go(UCIInputParser &uip);
64 }
65
66
67 ////
68 //// Functions
69 ////
70
71 /// uci_main_loop() is the only global function in this file.  It is
72 /// called immediately after the program has finished initializing.
73 /// The program remains in this loop until it receives the "quit" UCI
74 /// command.
75
76 void uci_main_loop() {
77
78   RootPosition.from_fen(StartPosition);
79
80   while (1)
81       get_command();
82 }
83
84
85 ////
86 //// Local functions
87 ////
88
89 namespace {
90
91   // get_command() waits for a command from the user, and passes
92   // this command to handle_command.  get_command also intercepts
93   // EOF from stdin, by translating EOF to the "quit" command.  This
94   // ensures that Stockfish exits gracefully if the GUI dies
95   // unexpectedly.
96
97   void get_command() {
98
99     std::string command;
100
101     if (!std::getline(std::cin, command))
102         command = "quit";
103
104     handle_command(command);
105   }
106
107
108   // handle_command() takes a text string as input, uses a
109   // UCIInputParser object to parse this text string as a UCI command,
110   // and calls the appropriate functions.  In addition to the UCI
111   // commands, the function also supports a few debug commands.
112
113   void handle_command(const std::string &command) {
114
115     UCIInputParser uip(command);
116     std::string token;
117
118     uip >> token; // operator >> skips any whitespace
119
120     if (token == "quit")
121     {
122         stop_threads();
123         quit_eval();
124         exit(0);
125     }
126     else if (token == "uci")
127     {
128         std::cout << "id name " << engine_name() << std::endl
129                   << "id author Tord Romstad, Marco Costalba"
130                   << std::endl;
131         print_uci_options();
132         std::cout << "uciok" << std::endl;
133     }
134     else if (token == "ucinewgame")
135     {
136         TT.clear();
137         Position::init_piece_square_tables();
138         RootPosition.from_fen(StartPosition);
139     }
140     else if (token == "isready")
141         std::cout << "readyok" << std::endl;
142     else if (token == "position")
143         set_position(uip);
144     else if (token == "setoption")
145         set_option(uip);
146     else if (token == "go")
147         go(uip);
148
149     // The remaining commands are for debugging purposes only.
150     // Perhaps they should be removed later in order to reduce the
151     // size of the program binary.
152     else if (token == "d")
153         RootPosition.print();
154     else if (token == "flip")
155     {
156         Position p(RootPosition);
157         RootPosition.flipped_copy(p);
158     }
159     else if (token == "eval")
160     {
161         EvalInfo ei;
162         std::cout << "Incremental mg: " << RootPosition.mg_value()
163                   << std::endl;
164         std::cout << "Incremental eg: " << RootPosition.eg_value()
165                   << std::endl;
166         std::cout << "Full eval: "
167                   << evaluate(RootPosition, ei, 0)
168                   << std::endl;
169     }
170     else if (token == "key")
171     {
172         std::cout << "key: " << std::hex << RootPosition.get_key()
173                   << " material key: " << RootPosition.get_material_key()
174                   << " pawn key: " << RootPosition.get_pawn_key()
175                   << std::endl;
176     }
177     else
178     {
179         std::cout << "Unknown command: " << command << std::endl;
180         while (!uip.eof())
181         {
182             uip >> token;
183             std::cout << token << std::endl;
184         }
185     }
186   }
187
188
189   // set_position() is called when Stockfish receives the "position" UCI
190   // command.  The input parameter is a UCIInputParser.  It is assumed
191   // that this parser has consumed the first token of the UCI command
192   // ("position"), and is ready to read the second token ("startpos"
193   // or "fen", if the input is well-formed).
194
195   void set_position(UCIInputParser &uip) {
196
197     std::string token;
198
199     uip >> token; // operator >> skips any whitespace
200
201     if (token == "startpos")
202         RootPosition.from_fen(StartPosition);
203     else if (token == "fen")
204     {
205         std::string fen;
206         while (token != "moves" && !uip.eof())
207         {
208           uip >> token;
209           fen += token;
210           fen += ' ';
211         }
212         RootPosition.from_fen(fen);
213     }
214
215     if (!uip.eof())
216     {
217         if (token != "moves")
218           uip >> token;
219         if (token == "moves")
220         {
221             Move move;
222             StateInfo st;
223             while (!uip.eof())
224             {
225                 uip >> token;
226                 move = move_from_string(RootPosition, token);
227                 RootPosition.do_move(move, st);
228                 if (RootPosition.rule_50_counter() == 0)
229                     RootPosition.reset_game_ply();
230             }
231             // Our StateInfo st is about going out of scope,
232             // so save its content before they disappear.
233             RootPosition.setStartState(st);
234         }
235     }
236   }
237
238
239   // set_option() is called when Stockfish receives the "setoption" UCI
240   // command.  The input parameter is a UCIInputParser.  It is assumed
241   // that this parser has consumed the first token of the UCI command
242   // ("setoption"), and is ready to read the second token ("name", if
243   // the input is well-formed).
244
245   void set_option(UCIInputParser &uip) {
246
247     std::string token, name;
248
249     uip >> token;
250     if (token == "name")
251     {
252         uip >> name;
253         while (!uip.eof())
254         {
255             uip >> token;
256             if (token == "value")
257                 break;
258
259             name += (" " + token);
260         }
261         if (token == "value")
262         {
263             std::getline(uip, token); // reads until end of line
264             set_option_value(name, token);
265         } else
266             push_button(name);
267     }
268   }
269
270
271   // go() is called when Stockfish receives the "go" UCI command.  The
272   // input parameter is a UCIInputParser.  It is assumed that this
273   // parser has consumed the first token of the UCI command ("go"),
274   // and is ready to read the second token.  The function sets the
275   // thinking time and other parameters from the input string, and
276   // calls think() (defined in search.cpp) with the appropriate
277   // parameters.
278
279   void go(UCIInputParser &uip) {
280
281     std::string token;
282
283     int time[2] = {0, 0}, inc[2] = {0, 0};
284     int movesToGo = 0, depth = 0, nodes = 0, moveTime = 0;
285     bool infinite = false, ponder = false;
286     Move searchMoves[500];
287
288     searchMoves[0] = MOVE_NONE;
289
290     while (!uip.eof())
291     {
292         uip >> token;
293
294         if (token == "infinite")
295             infinite = true;
296         else if (token == "ponder")
297             ponder = true;
298         else if (token == "wtime")
299             uip >> time[0];
300         else if (token == "btime")
301             uip >> time[1];
302         else if (token == "winc")
303             uip >> inc[0];
304         else if (token == "binc")
305             uip >> inc[1];
306         else if (token == "movestogo")
307             uip >> movesToGo;
308         else if (token == "depth")
309             uip >> depth;
310         else if (token == "nodes")
311             uip >> nodes;
312         else if (token == "movetime")
313             uip >> moveTime;
314         else if (token == "searchmoves")
315         {
316             int numOfMoves = 0;
317             while (!uip.eof())
318             {
319                 uip >> token;
320                 searchMoves[numOfMoves++] = move_from_string(RootPosition, token);
321             }
322             searchMoves[numOfMoves] = MOVE_NONE;
323         }
324     }
325
326     if (moveTime)
327         infinite = true;  // HACK
328
329     assert(RootPosition.is_ok());
330
331     think(RootPosition, infinite, ponder, RootPosition.side_to_move(), time,
332           inc, movesToGo, depth, nodes, moveTime, searchMoves);
333   }
334 }