Rev 96 | Rev 169 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
96 | pmbaty | 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-2015 Marco Costalba, Joona Kiiski, Tord Romstad |
||
5 | Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad |
||
6 | |||
7 | Stockfish is free software: you can redistribute it and/or modify |
||
8 | it under the terms of the GNU General Public License as published by |
||
9 | the Free Software Foundation, either version 3 of the License, or |
||
10 | (at your option) any later version. |
||
11 | |||
12 | Stockfish is distributed in the hope that it will be useful, |
||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
15 | GNU General Public License for more details. |
||
16 | |||
17 | You should have received a copy of the GNU General Public License |
||
18 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
||
19 | */ |
||
20 | |||
21 | #include <iostream> |
||
22 | #include <sstream> |
||
23 | #include <string> |
||
24 | |||
25 | #include "evaluate.h" |
||
26 | #include "movegen.h" |
||
27 | #include "position.h" |
||
28 | #include "search.h" |
||
29 | #include "thread.h" |
||
30 | #include "timeman.h" |
||
31 | #include "uci.h" |
||
32 | |||
33 | using namespace std; |
||
34 | |||
35 | extern void benchmark(const Position& pos, istream& is); |
||
36 | |||
37 | namespace { |
||
38 | |||
39 | // FEN string of the initial position, normal chess |
||
40 | const char* StartFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; |
||
41 | |||
154 | pmbaty | 42 | // A list to keep track of the position states along the setup moves (from the |
96 | pmbaty | 43 | // start position to the position just before the search starts). Needed by |
44 | // 'draw by repetition' detection. |
||
154 | pmbaty | 45 | StateListPtr States(new std::deque<StateInfo>(1)); |
96 | pmbaty | 46 | |
47 | |||
48 | // position() is called when engine receives the "position" UCI command. |
||
49 | // The function sets up the position described in the given FEN string ("fen") |
||
50 | // or the starting position ("startpos") and then makes the moves given in the |
||
51 | // following move list ("moves"). |
||
52 | |||
53 | void position(Position& pos, istringstream& is) { |
||
54 | |||
55 | Move m; |
||
56 | string token, fen; |
||
57 | |||
58 | is >> token; |
||
59 | |||
60 | if (token == "startpos") |
||
61 | { |
||
62 | fen = StartFEN; |
||
63 | is >> token; // Consume "moves" token if any |
||
64 | } |
||
65 | else if (token == "fen") |
||
66 | while (is >> token && token != "moves") |
||
67 | fen += token + " "; |
||
68 | else |
||
69 | return; |
||
70 | |||
154 | pmbaty | 71 | States = StateListPtr(new std::deque<StateInfo>(1)); |
72 | pos.set(fen, Options["UCI_Chess960"], &States->back(), Threads.main()); |
||
96 | pmbaty | 73 | |
74 | // Parse move list (if any) |
||
75 | while (is >> token && (m = UCI::to_move(pos, token)) != MOVE_NONE) |
||
76 | { |
||
154 | pmbaty | 77 | States->push_back(StateInfo()); |
78 | pos.do_move(m, States->back(), pos.gives_check(m)); |
||
96 | pmbaty | 79 | } |
80 | } |
||
81 | |||
82 | |||
83 | // setoption() is called when engine receives the "setoption" UCI command. The |
||
84 | // function updates the UCI option ("name") to the given value ("value"). |
||
85 | |||
86 | void setoption(istringstream& is) { |
||
87 | |||
88 | string token, name, value; |
||
89 | |||
90 | is >> token; // Consume "name" token |
||
91 | |||
92 | // Read option name (can contain spaces) |
||
93 | while (is >> token && token != "value") |
||
94 | name += string(" ", name.empty() ? 0 : 1) + token; |
||
95 | |||
96 | // Read option value (can contain spaces) |
||
97 | while (is >> token) |
||
98 | value += string(" ", value.empty() ? 0 : 1) + token; |
||
99 | |||
100 | if (Options.count(name)) |
||
101 | Options[name] = value; |
||
102 | else |
||
103 | sync_cout << "No such option: " << name << sync_endl; |
||
104 | } |
||
105 | |||
106 | |||
107 | // go() is called when engine receives the "go" UCI command. The function sets |
||
108 | // the thinking time and other parameters from the input string, then starts |
||
109 | // the search. |
||
110 | |||
154 | pmbaty | 111 | void go(Position& pos, istringstream& is) { |
96 | pmbaty | 112 | |
113 | Search::LimitsType limits; |
||
114 | string token; |
||
115 | |||
116 | limits.startTime = now(); // As early as possible! |
||
117 | |||
118 | while (is >> token) |
||
119 | if (token == "searchmoves") |
||
120 | while (is >> token) |
||
121 | limits.searchmoves.push_back(UCI::to_move(pos, token)); |
||
122 | |||
123 | else if (token == "wtime") is >> limits.time[WHITE]; |
||
124 | else if (token == "btime") is >> limits.time[BLACK]; |
||
125 | else if (token == "winc") is >> limits.inc[WHITE]; |
||
126 | else if (token == "binc") is >> limits.inc[BLACK]; |
||
127 | else if (token == "movestogo") is >> limits.movestogo; |
||
128 | else if (token == "depth") is >> limits.depth; |
||
129 | else if (token == "nodes") is >> limits.nodes; |
||
130 | else if (token == "movetime") is >> limits.movetime; |
||
131 | else if (token == "mate") is >> limits.mate; |
||
132 | else if (token == "infinite") limits.infinite = 1; |
||
133 | else if (token == "ponder") limits.ponder = 1; |
||
134 | |||
154 | pmbaty | 135 | Threads.start_thinking(pos, States, limits); |
96 | pmbaty | 136 | } |
137 | |||
138 | } // namespace |
||
139 | |||
140 | |||
141 | /// UCI::loop() waits for a command from stdin, parses it and calls the appropriate |
||
142 | /// function. Also intercepts EOF from stdin to ensure gracefully exiting if the |
||
143 | /// GUI dies unexpectedly. When called with some command line arguments, e.g. to |
||
144 | /// run 'bench', once the command is executed the function returns immediately. |
||
145 | /// In addition to the UCI ones, also some additional debug commands are supported. |
||
146 | |||
147 | void UCI::loop(int argc, char* argv[]) { |
||
148 | |||
154 | pmbaty | 149 | Position pos; |
96 | pmbaty | 150 | string token, cmd; |
151 | |||
154 | pmbaty | 152 | pos.set(StartFEN, false, &States->back(), Threads.main()); |
153 | |||
96 | pmbaty | 154 | for (int i = 1; i < argc; ++i) |
155 | cmd += std::string(argv[i]) + " "; |
||
156 | |||
157 | do { |
||
158 | if (argc == 1 && !getline(cin, cmd)) // Block here waiting for input or EOF |
||
159 | cmd = "quit"; |
||
160 | |||
161 | istringstream is(cmd); |
||
162 | |||
163 | token.clear(); // getline() could return empty or blank line |
||
164 | is >> skipws >> token; |
||
165 | |||
166 | // The GUI sends 'ponderhit' to tell us to ponder on the same move the |
||
167 | // opponent has played. In case Signals.stopOnPonderhit is set we are |
||
168 | // waiting for 'ponderhit' to stop the search (for instance because we |
||
169 | // already ran out of time), otherwise we should continue searching but |
||
170 | // switching from pondering to normal search. |
||
171 | if ( token == "quit" |
||
172 | || token == "stop" |
||
173 | || (token == "ponderhit" && Search::Signals.stopOnPonderhit)) |
||
174 | { |
||
175 | Search::Signals.stop = true; |
||
176 | Threads.main()->start_searching(true); // Could be sleeping |
||
177 | } |
||
178 | else if (token == "ponderhit") |
||
179 | Search::Limits.ponder = 0; // Switch to normal search |
||
180 | |||
181 | else if (token == "uci") |
||
182 | sync_cout << "id name " << engine_info(true) |
||
183 | << "\n" << Options |
||
184 | << "\nuciok" << sync_endl; |
||
185 | |||
186 | else if (token == "ucinewgame") |
||
187 | { |
||
188 | Search::clear(); |
||
189 | Time.availableNodes = 0; |
||
190 | } |
||
191 | else if (token == "isready") sync_cout << "readyok" << sync_endl; |
||
192 | else if (token == "go") go(pos, is); |
||
193 | else if (token == "position") position(pos, is); |
||
194 | else if (token == "setoption") setoption(is); |
||
195 | |||
196 | // Additional custom non-UCI commands, useful for debugging |
||
197 | else if (token == "flip") pos.flip(); |
||
198 | else if (token == "bench") benchmark(pos, is); |
||
199 | else if (token == "d") sync_cout << pos << sync_endl; |
||
200 | else if (token == "eval") sync_cout << Eval::trace(pos) << sync_endl; |
||
201 | else if (token == "perft") |
||
202 | { |
||
203 | int depth; |
||
204 | stringstream ss; |
||
205 | |||
206 | is >> depth; |
||
207 | ss << Options["Hash"] << " " |
||
208 | << Options["Threads"] << " " << depth << " current perft"; |
||
209 | |||
210 | benchmark(pos, ss); |
||
211 | } |
||
212 | else |
||
213 | sync_cout << "Unknown command: " << cmd << sync_endl; |
||
214 | |||
215 | } while (token != "quit" && argc == 1); // Passed args have one-shot behaviour |
||
216 | |||
217 | Threads.main()->wait_for_search_finished(); |
||
218 | } |
||
219 | |||
220 | |||
221 | /// UCI::value() converts a Value to a string suitable for use with the UCI |
||
222 | /// protocol specification: |
||
223 | /// |
||
224 | /// cp <x> The score from the engine's point of view in centipawns. |
||
225 | /// mate <y> Mate in y moves, not plies. If the engine is getting mated |
||
226 | /// use negative values for y. |
||
227 | |||
228 | string UCI::value(Value v) { |
||
229 | |||
230 | stringstream ss; |
||
231 | |||
232 | if (abs(v) < VALUE_MATE - MAX_PLY) |
||
233 | ss << "cp " << v * 100 / PawnValueEg; |
||
234 | else |
||
235 | ss << "mate " << (v > 0 ? VALUE_MATE - v + 1 : -VALUE_MATE - v) / 2; |
||
236 | |||
237 | return ss.str(); |
||
238 | } |
||
239 | |||
240 | |||
241 | /// UCI::square() converts a Square to a string in algebraic notation (g1, a7, etc.) |
||
242 | |||
243 | std::string UCI::square(Square s) { |
||
244 | return std::string{ char('a' + file_of(s)), char('1' + rank_of(s)) }; |
||
245 | } |
||
246 | |||
247 | |||
248 | /// UCI::move() converts a Move to a string in coordinate notation (g1f3, a7a8q). |
||
249 | /// The only special case is castling, where we print in the e1g1 notation in |
||
250 | /// normal chess mode, and in e1h1 notation in chess960 mode. Internally all |
||
251 | /// castling moves are always encoded as 'king captures rook'. |
||
252 | |||
253 | string UCI::move(Move m, bool chess960) { |
||
254 | |||
255 | Square from = from_sq(m); |
||
256 | Square to = to_sq(m); |
||
257 | |||
258 | if (m == MOVE_NONE) |
||
259 | return "(none)"; |
||
260 | |||
261 | if (m == MOVE_NULL) |
||
262 | return "0000"; |
||
263 | |||
264 | if (type_of(m) == CASTLING && !chess960) |
||
265 | to = make_square(to > from ? FILE_G : FILE_C, rank_of(from)); |
||
266 | |||
267 | string move = UCI::square(from) + UCI::square(to); |
||
268 | |||
269 | if (type_of(m) == PROMOTION) |
||
270 | move += " pnbrqk"[promotion_type(m)]; |
||
271 | |||
272 | return move; |
||
273 | } |
||
274 | |||
275 | |||
276 | /// UCI::to_move() converts a string representing a move in coordinate notation |
||
277 | /// (g1f3, a7a8q) to the corresponding legal Move, if any. |
||
278 | |||
279 | Move UCI::to_move(const Position& pos, string& str) { |
||
280 | |||
281 | if (str.length() == 5) // Junior could send promotion piece in uppercase |
||
282 | str[4] = char(tolower(str[4])); |
||
283 | |||
284 | for (const auto& m : MoveList<LEGAL>(pos)) |
||
285 | if (str == UCI::move(m, pos.is_chess960())) |
||
286 | return m; |
||
287 | |||
288 | return MOVE_NONE; |
||
289 | } |