1 /* Copyright (C) 2007-2011 Vincent Ollivier
3 * Purple Haze is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
8 * Purple Haze is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
31 static const std::string OPTIONS
[][2] = {
42 "set the board according to <fen> position"
46 "count all nodes at each depth from the starting position"
50 "count all nodes from each moves at the starting position"
53 "testsuite <epd> [<time>]",
54 "search each position of <epd> for <time> seconds"
58 "compare perft results to each position of <epd>"
62 "start XBoard protocole mode"
78 int main(int argc
, char *argv
[])
80 bool option_color
= false;
82 while ((opt
= getopt(argc
, argv
, "c")) != -1) {
89 std::cout
<< "Purple Haze " << VERSION
<< std::endl
;
90 std::cout
<< std::endl
;
92 // Parse commands from CLI
93 std::string
init_fen(DEFAULT_FEN
);
94 for (std::string cmd
= prompt(); cmd
!= "quit"; cmd
= prompt()) {
95 if (cmd
== "xboard") { // Xboard protocol mode
99 } else if (cmd
== "help") {
100 std::cout
<< std::left
;
103 for (const std::string (&option
)[2] : OPTIONS
) {
104 std::string name
= option
[0];
105 std::string usage
= option
[1];
106 std::cout
<< std::setw(comm_width
) << name
107 << std::setw(desc_width
) << usage
110 } else if (cmd
== "version") {
111 std::cout
<< VERSION
<< std::endl
;
112 } else if (cmd
== "setboard") { // Get FEN
113 getline(std::cin
, init_fen
);
114 init_fen
.erase(0, 1); // Remove the first whitespace
115 } else if (cmd
== "perft") {
118 for (unsigned int i
= 1; ; ++i
) {
119 clock_t starting_time
= clock();
120 unsigned long long int perft_result
= game
.perft(i
);
121 long double elapsed
= clock() - starting_time
;
122 long double perft_time
= elapsed
/ CLOCKS_PER_SEC
;
123 std::cout
<< "Perft(" << i
<< ") = " << perft_result
;
124 std::cout
<< " (" << perft_time
<< " secs, ";
125 std::cout
<< perft_result
/ perft_time
<< " nps)" << std::endl
;
127 } else if (cmd
== "divide") {
130 std::cout
<< std::endl
;
133 Color c
= game
.current_position().get_turn_color();
134 unsigned int nodes_count
= 0;
135 unsigned int moves_count
= 0;
136 Moves
moves(game
.board
, game
.pieces
, game
.current_position(),
139 while (!(move
= moves
.next()).is_null()) {
140 game
.make_move(move
);
141 if (!game
.is_check(c
)) {
142 unsigned int cnt
= game
.perft(depth
- 1);
145 std::cout
<< move
<< " " << cnt
<< std::endl
;
147 game
.undo_move(move
);
149 std::cout
<< std::endl
;
150 std::cout
<< "Moves: " << moves_count
<< std::endl
;
151 std::cout
<< "Positions: " << nodes_count
<< std::endl
;
152 } else if (cmd
== "testsuite") { // Load EPD test suite
153 std::string filename
;
154 std::cin
>> filename
;
156 // Check if filename exists
157 std::ifstream epdfile
;
158 epdfile
.open(filename
.c_str());
159 if (!epdfile
.is_open()) {
160 std::cerr
<< "Cannot open '" << filename
;
161 std::cerr
<< "': No such file or directory" << std::endl
;
164 // Get time per move (optional)
166 getline(std::cin
, seconds
);
169 std::istringstream
iss(seconds
);
173 std::cout
<< "Loading '" << filename
<< "', ";
174 std::cout
<< time
<< "s per move" << std::endl
; // In seconds
176 // Load game protocol
178 proto
.set_output_thinking(false);
179 proto
.set_time(1, time
);
181 // Read positions in file
182 unsigned int res
= 0;
185 while (getline(epdfile
, line
)) {
187 // TODO: add am (avoid move)
188 size_t fensep
= line
.find(" bm ");
189 size_t bmsep
= line
.find(";");
190 size_t not_found
= std::string::npos
;
191 if (fensep
== not_found
|| bmsep
== not_found
) continue;
193 // Load position in game
194 init_fen
= line
.substr(0, fensep
);
195 std::cout
<< "Loading position #" << i
+ 1
196 << " '" << init_fen
<< "' ";
197 proto
.set_board(init_fen
);
199 // Search best move and test it
200 std::string best_moves
= line
.substr(fensep
+ 4,
202 std::cout
<< "bm " << best_moves
;
203 std::string move
= proto
.search_move(true);
204 std::cout
<< " => " << move
;
205 std::istringstream
iss(best_moves
);
206 bool is_found
= false;
208 std::string best_move
;
210 if (best_move
== move
) {
217 if (option_color
) std::cout
<< color_green
;
221 if (option_color
) std::cout
<< color_red
;
224 if (option_color
) std::cout
<< color_reset
;
225 std::cout
<< std::endl
;
228 std::cout
<< "Result: " << res
<< "/" << i
<< std::endl
;
230 } else if (cmd
== "perftsuite") { // Load perft test suite
231 std::string filename
;
232 std::cin
>> filename
;
233 std::ifstream epdfile
;
234 epdfile
.open(filename
.c_str());
235 if (!epdfile
.is_open()) {
236 std::cerr
<< "Cannot open '" << filename
<< "': "
237 << "No such file or directory" << std::endl
;
239 const size_t npos
= std::string::npos
;
241 while (getline(epdfile
, line
)) {
244 for (int i
= 0; line
.length() > 0; ++i
) {
246 const size_t pos
= line
.find(" ;");
247 std::string sub
= line
.substr(0, pos
);
248 line
= (pos
!= npos
? line
.substr(pos
+ 2, npos
) : "");
253 std::cout
<< "FEN '" << fen
<< "': " << std::flush
;
255 sub
= sub
.substr(3, npos
); // Skip /^D\d /
256 unsigned int moves
= game
.perft(i
);
257 unsigned int expected
;
258 std::istringstream(sub
) >> expected
;
260 std::cout
<< (moves
== expected
? color_green
263 std::cout
<< (moves
== expected
? "." : "x")
264 << (option_color
? color_reset
: "")
268 std::cout
<< std::endl
;