Rename '<time.h>' to '<ctime>'
[purplehaze.git] / src / main.cpp
blobebf0d7f1ca370bc1eb4fefa1361f0eb2e4c870ff
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/>.
17 #include <assert.h>
18 #include <fstream>
19 #include <getopt.h>
20 #include <iomanip>
21 #include <iostream>
22 #include <sstream>
23 #include <stdio.h>
24 #include <string>
25 #include <ctime>
27 #include "common.h"
28 #include "game.h"
29 #include "xboard.h"
31 static const std::string OPTIONS[][2] = {
33 "help",
34 "display this screen"
37 "version",
38 "display the version"
41 "setboard",
42 "set the board according to <fen> position"
45 "perft",
46 "count all nodes at each depth from the starting position"
49 "divide",
50 "count all nodes from each moves at the starting position"
53 "testsuite <epd> [<time>]",
54 "search each position of <epd> for <time> seconds"
57 "perftsuite <epd>",
58 "compare perft results to each position of <epd>"
61 "xboard",
62 "start XBoard protocole mode"
65 "quit",
66 "exit Purple Haze"
70 std::string prompt()
72 std::cout << "> ";
73 std::string cmd;
74 std::cin >> cmd;
75 return cmd;
78 int main(int argc, char *argv[])
80 bool option_color = false;
81 char opt;
82 while ((opt = getopt(argc, argv, "c")) != -1) {
83 switch (opt) {
84 case 'c':
85 option_color = true;
86 break;
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
96 Xboard xboard;
97 xboard.loop();
98 return 0;
99 } else if (cmd == "help") {
100 std::cout << std::left;
101 int comm_width = 30;
102 int desc_width = 50;
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
108 << std::endl;
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") {
116 Game game;
117 game.init(init_fen);
118 for (unsigned int i = 1; ; ++i) {
119 clock_t start = clock();
120 unsigned long long int perft_result = game.perft(i);
121 long double clocks = clock() - start;
122 long double perft_time = clocks / 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") {
128 int depth = 0;
129 std::cin >> depth;
130 std::cout << std::endl;
131 Game game;
132 game.init(init_fen);
133 Color c = game.current_position().side();
134 unsigned int nodes_count = 0;
135 unsigned int moves_count = 0;
136 Moves moves(game.board, game.pieces, game.current_position(),
137 game.search_moves);
138 Move move;
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);
143 nodes_count += cnt;
144 ++moves_count;
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)
165 std::string seconds;
166 getline(std::cin, seconds);
167 int time = 10;
168 if (seconds != "") {
169 std::istringstream iss(seconds);
170 iss >> time;
173 std::cout << "Loading '" << filename << "', ";
174 std::cout << time << "s per move" << std::endl; // In seconds
176 // Load game protocol
177 Protocol proto;
178 proto.set_output_thinking(false);
179 proto.set_time(1, time);
181 // Read positions in file
182 unsigned int res = 0;
183 unsigned int i = 0;
184 std::string line;
185 while (getline(epdfile, line)) {
186 proto.new_game();
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 << "FEN #" << i + 1 << " '" << init_fen << "' ";
196 proto.set_board(init_fen);
198 // Search best move and test it
199 std::string best_moves = line.substr(fensep + 4,
200 bmsep - fensep - 4);
201 std::cout << "bm " << best_moves;
202 std::string move = proto.search_move(true);
203 std::cout << " => " << move;
204 std::istringstream iss(best_moves);
205 bool is_found = false;
206 do {
207 std::string best_move;
208 iss >> best_move;
209 if (best_move == move) {
210 is_found = true;
211 break;
213 } while (iss);
215 if (is_found) {
216 if (option_color) std::cout << color_green;
217 std::cout << " OK";
218 ++res;
219 } else {
220 if (option_color) std::cout << color_red;
221 std::cout << " KO";
223 if (option_color) std::cout << color_reset;
224 std::cout << std::endl;
225 ++i;
227 std::cout << "Result: " << res << "/" << i << std::endl;
228 epdfile.close();
229 } else if (cmd == "perftsuite") { // Load perft test suite
230 std::string filename;
231 std::cin >> filename;
232 std::ifstream epdfile;
233 epdfile.open(filename.c_str());
234 if (!epdfile.is_open()) {
235 std::cerr << "Cannot open '" << filename << "': "
236 << "No such file or directory" << std::endl;
238 const size_t npos = std::string::npos;
239 std::string line;
240 while (getline(epdfile, line)) {
241 std::string fen;
242 Game game;
243 for (int i = 0; line.length() > 0; ++i) {
245 const size_t pos = line.find(" ;");
246 std::string sub = line.substr(0, pos);
247 line = (pos != npos ? line.substr(pos + 2, npos) : "");
249 if (i == 0) {
250 fen = sub;
251 game.init(fen);
252 std::cout << "FEN '" << fen << "': " << std::flush;
253 } else {
254 sub = sub.substr(3, npos); // Skip /^D\d /
255 unsigned int moves = game.perft(i);
256 unsigned int expected;
257 std::istringstream(sub) >> expected;
258 if (option_color) {
259 std::cout << (moves == expected ? color_green
260 : color_red);
262 std::cout << (moves == expected ? "." : "x")
263 << (option_color ? color_reset : "")
264 << std::flush;
267 std::cout << std::endl;
269 epdfile.close();
272 return 0;