Rev 154 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 154 | Rev 169 | ||
|---|---|---|---|
| Line 4... | Line 4... | ||
| 4 | Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad |
4 | Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad |
| 5 | Copyright (C) 2015- |
5 | Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad |
| 6 | 6 | ||
| 7 | Stockfish is free software: you can redistribute it and/or modify |
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 |
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 |
9 | the Free Software Foundation, either version 3 of the License, or |
| 10 | (at your option) any later version. |
10 | (at your option) any later version. |
| Line 16... | Line 16... | ||
| 16 | 16 | ||
| 17 | You should have received a copy of the GNU General Public License |
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/>. |
18 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 19 | */ |
19 | */ |
| 20 | 20 | ||
| - | 21 | #include <cassert> |
|
| 21 | #include <iostream> |
22 | #include <iostream> |
| 22 | #include <sstream> |
23 | #include <sstream> |
| 23 | #include <string> |
24 | #include <string> |
| 24 | 25 | ||
| 25 | #include "evaluate.h" |
26 | #include "evaluate.h" |
| 26 | #include "movegen.h" |
27 | #include "movegen.h" |
| 27 | #include "position.h" |
28 | #include "position.h" |
| 28 | #include "search.h" |
29 | #include "search.h" |
| 29 | #include "thread.h" |
30 | #include "thread.h" |
| - | 31 | #include "tt.h" |
|
| 30 | #include "timeman.h" |
32 | #include "timeman.h" |
| 31 | #include "uci.h" |
33 | #include "uci.h" |
| - | 34 | #include "syzygy/tbprobe.h" |
|
| 32 | 35 | ||
| 33 | using namespace std; |
36 | using namespace std; |
| 34 | 37 | ||
| 35 | extern |
38 | extern vector<string> setup_bench(const Position&, istream&); |
| 36 | 39 | ||
| 37 | namespace { |
40 | namespace { |
| 38 | 41 | ||
| 39 | // FEN string of the initial position, normal chess |
42 | // FEN string of the initial position, normal chess |
| 40 | const char* StartFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; |
43 | const char* StartFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; |
| 41 | - | ||
| 42 | // A list to keep track of the position states along the setup moves (from the |
- | |
| 43 | // start position to the position just before the search starts). Needed by |
- | |
| 44 | // 'draw by repetition' detection. |
- | |
| 45 | StateListPtr States(new std::deque<StateInfo>(1)); |
- | |
| 46 | 44 | ||
| 47 | 45 | ||
| 48 | // position() is called when engine receives the "position" UCI command. |
46 | // position() is called when engine receives the "position" UCI command. |
| 49 | // The function sets up the position described in the given FEN string ("fen") |
47 | // 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 |
48 | // or the starting position ("startpos") and then makes the moves given in the |
| 51 | // following move list ("moves"). |
49 | // following move list ("moves"). |
| 52 | 50 | ||
| 53 | void position(Position& pos, istringstream& |
51 | void position(Position& pos, istringstream& is, StateListPtr& states) { |
| 54 | 52 | ||
| 55 | Move m; |
53 | Move m; |
| 56 | string token, fen; |
54 | string token, fen; |
| 57 | 55 | ||
| 58 | is >> token; |
56 | is >> token; |
| Line 66... | Line 64... | ||
| 66 | while (is >> token && token != "moves") |
64 | while (is >> token && token != "moves") |
| 67 | fen += token + " "; |
65 | fen += token + " "; |
| 68 | else |
66 | else |
| 69 | return; |
67 | return; |
| 70 | 68 | ||
| 71 |
|
69 | states = StateListPtr(new std::deque<StateInfo>(1)); // Drop old and create a new one |
| 72 | pos.set(fen, Options["UCI_Chess960"], & |
70 | pos.set(fen, Options["UCI_Chess960"], &states->back(), Threads.main()); |
| 73 | 71 | ||
| 74 | // Parse move list (if any) |
72 | // Parse move list (if any) |
| 75 | while (is >> token && (m = UCI::to_move(pos, token)) != MOVE_NONE) |
73 | while (is >> token && (m = UCI::to_move(pos, token)) != MOVE_NONE) |
| 76 | { |
74 | { |
| 77 |
|
75 | states->emplace_back(); |
| 78 | pos.do_move(m, |
76 | pos.do_move(m, states->back()); |
| 79 | } |
77 | } |
| 80 | } |
78 | } |
| 81 | 79 | ||
| 82 | 80 | ||
| 83 | // setoption() is called when engine receives the "setoption" UCI command. The |
81 | // setoption() is called when engine receives the "setoption" UCI command. The |
| Line 106... | Line 104... | ||
| 106 | 104 | ||
| 107 | // go() is called when engine receives the "go" UCI command. The function sets |
105 | // 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 |
106 | // the thinking time and other parameters from the input string, then starts |
| 109 | // the search. |
107 | // the search. |
| 110 | 108 | ||
| 111 | void go(Position& pos, istringstream& |
109 | void go(Position& pos, istringstream& is, StateListPtr& states) { |
| 112 | 110 | ||
| 113 | Search::LimitsType limits; |
111 | Search::LimitsType limits; |
| 114 | string token; |
112 | string token; |
| - | 113 | bool ponderMode = false; |
|
| 115 | 114 | ||
| 116 | limits.startTime = now(); // As early as possible! |
115 | limits.startTime = now(); // As early as possible! |
| 117 | 116 | ||
| 118 | while (is >> token) |
117 | while (is >> token) |
| 119 | if (token == "searchmoves") |
118 | if (token == "searchmoves") |
| Line 127... | Line 126... | ||
| 127 | else if (token == "movestogo") is >> limits.movestogo; |
126 | else if (token == "movestogo") is >> limits.movestogo; |
| 128 | else if (token == "depth") is >> limits.depth; |
127 | else if (token == "depth") is >> limits.depth; |
| 129 | else if (token == "nodes") is >> limits.nodes; |
128 | else if (token == "nodes") is >> limits.nodes; |
| 130 | else if (token == "movetime") is >> limits.movetime; |
129 | else if (token == "movetime") is >> limits.movetime; |
| 131 | else if (token == "mate") is >> limits.mate; |
130 | else if (token == "mate") is >> limits.mate; |
| - | 131 | else if (token == "perft") is >> limits.perft; |
|
| 132 | else if (token == "infinite") limits.infinite = 1; |
132 | else if (token == "infinite") limits.infinite = 1; |
| 133 | else if (token == "ponder") |
133 | else if (token == "ponder") ponderMode = true; |
| 134 | 134 | ||
| 135 | Threads.start_thinking(pos, |
135 | Threads.start_thinking(pos, states, limits, ponderMode); |
| - | 136 | } |
|
| - | 137 | ||
| - | 138 | ||
| - | 139 | // bench() is called when engine receives the "bench" command. Firstly |
|
| - | 140 | // a list of UCI commands is setup according to bench parameters, then |
|
| - | 141 | // it is run one by one printing a summary at the end. |
|
| - | 142 | ||
| - | 143 | void bench(Position& pos, istream& args, StateListPtr& states) { |
|
| - | 144 | ||
| - | 145 | string token; |
|
| - | 146 | uint64_t num, nodes = 0, cnt = 1; |
|
| - | 147 | ||
| - | 148 | vector<string> list = setup_bench(pos, args); |
|
| - | 149 | num = count_if(list.begin(), list.end(), [](string s) { return s.find("go ") == 0; }); |
|
| - | 150 | ||
| - | 151 | TimePoint elapsed = now(); |
|
| - | 152 | ||
| - | 153 | for (const auto& cmd : list) |
|
| - | 154 | { |
|
| - | 155 | istringstream is(cmd); |
|
| - | 156 | is >> skipws >> token; |
|
| - | 157 | ||
| - | 158 | if (token == "go") |
|
| - | 159 | { |
|
| - | 160 | cerr << "\nPosition: " << cnt++ << '/' << num << endl; |
|
| - | 161 | go(pos, is, states); |
|
| - | 162 | Threads.main()->wait_for_search_finished(); |
|
| - | 163 | nodes += Threads.nodes_searched(); |
|
| - | 164 | } |
|
| - | 165 | else if (token == "setoption") setoption(is); |
|
| - | 166 | else if (token == "position") position(pos, is, states); |
|
| - | 167 | else if (token == "ucinewgame") Search::clear(); |
|
| - | 168 | } |
|
| - | 169 | ||
| - | 170 | elapsed = now() - elapsed + 1; // Ensure positivity to avoid a 'divide by zero' |
|
| - | 171 | ||
| - | 172 | dbg_print(); // Just before exiting |
|
| - | 173 | ||
| - | 174 | cerr << "\n===========================" |
|
| - | 175 | << "\nTotal time (ms) : " << elapsed |
|
| - | 176 | << "\nNodes searched : " << nodes |
|
| - | 177 | << "\nNodes/second : " << 1000 * nodes / elapsed << endl; |
|
| 136 | } |
178 | } |
| 137 | 179 | ||
| 138 | } // namespace |
180 | } // namespace |
| 139 | 181 | ||
| 140 | 182 | ||
| Line 146... | Line 188... | ||
| 146 | 188 | ||
| 147 | void UCI::loop(int argc, char* argv[]) { |
189 | void UCI::loop(int argc, char* argv[]) { |
| 148 | 190 | ||
| 149 | Position pos; |
191 | Position pos; |
| 150 | string token, cmd; |
192 | string token, cmd; |
| - | 193 | StateListPtr states(new std::deque<StateInfo>(1)); |
|
| - | 194 | auto uiThread = std::make_shared<Thread>(0); |
|
| 151 | 195 | ||
| 152 | pos.set(StartFEN, false, & |
196 | pos.set(StartFEN, false, &states->back(), uiThread.get()); |
| 153 | 197 | ||
| 154 | for (int i = 1; i < argc; ++i) |
198 | for (int i = 1; i < argc; ++i) |
| 155 | cmd += std::string(argv[i]) + " "; |
199 | cmd += std::string(argv[i]) + " "; |
| 156 | 200 | ||
| 157 | do { |
201 | do { |
| 158 | if (argc == 1 && !getline(cin, cmd)) // Block here waiting for input or EOF |
202 | if (argc == 1 && !getline(cin, cmd)) // Block here waiting for input or EOF |
| 159 | cmd = "quit"; |
203 | cmd = "quit"; |
| 160 | 204 | ||
| 161 | istringstream is(cmd); |
205 | istringstream is(cmd); |
| 162 | 206 | ||
| 163 | token.clear(); // getline() |
207 | token.clear(); // Avoid a stale if getline() returns empty or blank line |
| 164 | is >> skipws >> token; |
208 | is >> skipws >> token; |
| 165 | 209 | ||
| 166 | // The GUI sends 'ponderhit' to tell us |
210 | // The GUI sends 'ponderhit' to tell us the user has played the expected move. |
| 167 | // |
211 | // So 'ponderhit' will be sent if we were told to ponder on the same move the |
| 168 | // |
212 | // user has played. We should continue searching but switch from pondering to |
| 169 | // |
213 | // normal search. In case Threads.stopOnPonderhit is set we are waiting for |
| 170 | // |
214 | // 'ponderhit' to stop the search, for instance if max search depth is reached. |
| 171 | if ( token == "quit" |
215 | if ( token == "quit" |
| 172 | || token == "stop" |
216 | || token == "stop" |
| 173 | || (token == "ponderhit" && |
217 | || (token == "ponderhit" && Threads.stopOnPonderhit)) |
| 174 | { |
- | |
| 175 |
|
218 | Threads.stop = true; |
| 176 | Threads.main()->start_searching(true); // Could be sleeping |
- | |
| 177 | } |
219 | |
| 178 | else if (token == "ponderhit") |
220 | else if (token == "ponderhit") |
| 179 |
|
221 | Threads.ponder = false; // Switch to normal search |
| 180 | 222 | ||
| 181 | else if (token == "uci") |
223 | else if (token == "uci") |
| 182 | sync_cout << "id name " << engine_info(true) |
224 | sync_cout << "id name " << engine_info(true) |
| 183 | << "\n" << Options |
225 | << "\n" << Options |
| 184 | << "\nuciok" << sync_endl; |
226 | << "\nuciok" << sync_endl; |
| 185 | 227 | ||
| 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); |
228 | else if (token == "setoption") setoption(is); |
| - | 229 | else if (token == "go") go(pos, is, states); |
|
| - | 230 | else if (token == "position") position(pos, is, states); |
|
| - | 231 | else if (token == "ucinewgame") Search::clear(); |
|
| - | 232 | else if (token == "isready") sync_cout << "readyok" << sync_endl; |
|
| 195 | 233 | ||
| 196 | // Additional custom non-UCI commands, |
234 | // Additional custom non-UCI commands, mainly for debugging |
| 197 | else if (token == "flip") |
235 | else if (token == "flip") pos.flip(); |
| 198 | else if (token == "bench") |
236 | else if (token == "bench") bench(pos, is, states); |
| 199 | else if (token == "d") |
237 | else if (token == "d") sync_cout << pos << sync_endl; |
| 200 | else if (token == "eval") |
238 | 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 |
239 | else |
| 213 | sync_cout << "Unknown command: " << cmd << sync_endl; |
240 | sync_cout << "Unknown command: " << cmd << sync_endl; |
| 214 | 241 | ||
| 215 | } while (token != "quit" && argc == 1); // |
242 | } while (token != "quit" && argc == 1); // Command line args are one-shot |
| 216 | - | ||
| 217 | Threads.main()->wait_for_search_finished(); |
- | |
| 218 | } |
243 | } |
| 219 | 244 | ||
| 220 | 245 | ||
| 221 | /// UCI::value() converts a Value to a string suitable for use with the UCI |
246 | /// UCI::value() converts a Value to a string suitable for use with the UCI |
| 222 | /// protocol specification: |
247 | /// protocol specification: |
| Line 224... | Line 249... | ||
| 224 | /// cp <x> The score from the engine's point of view in centipawns. |
249 | /// 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 |
250 | /// mate <y> Mate in y moves, not plies. If the engine is getting mated |
| 226 | /// use negative values for y. |
251 | /// use negative values for y. |
| 227 | 252 | ||
| 228 | string UCI::value(Value v) { |
253 | string UCI::value(Value v) { |
| - | 254 | ||
| - | 255 | assert(-VALUE_INFINITE < v && v < VALUE_INFINITE); |
|
| 229 | 256 | ||
| 230 | stringstream ss; |
257 | stringstream ss; |
| 231 | 258 | ||
| 232 | if (abs(v) < VALUE_MATE - MAX_PLY) |
259 | if (abs(v) < VALUE_MATE - MAX_PLY) |
| 233 | ss << "cp " << v * 100 / PawnValueEg; |
260 | ss << "cp " << v * 100 / PawnValueEg; |