1 /* main.cpp
2 
3    GNU Chess protocol adapter
4 
5    Copyright (C) 2001-2015 Free Software Foundation, Inc.
6 
7    This program 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    This program 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 
22 // main.cpp
23 
24 // includes
25 
26 #include <pthread.h>
27 #include <cerrno>
28 #include <csignal>
29 #include <cstdio>
30 #include <cstdlib>
31 #include <cstring>
32 
33 #include "adapter.h"
34 #include "attack.h"
35 #include "board.h"
36 #include "book.h"
37 #include "book_make.h"
38 #include "book_merge.h"
39 #include "engine.h"
40 #include "epd.h"
41 #include "fen.h"
42 #include "hash.h"
43 #include "list.h"
44 #include "main.h"
45 #include "move.h"
46 #include "move_gen.h"
47 #include "option.h"
48 #include "piece.h"
49 #include "search.h"
50 #include "square.h"
51 #include "uci.h"
52 #include "util.h"
53 
54 namespace adapter {
55 
56 // constants
57 
58 static const char * const Version = "1.4";
59 
60 static const bool BlockSignal = false; // true on Windows
61 
62 static const int SearchDepth = 63;
63 static const double SearchTime = 3600.0;
64 
65 static const int StringSize = 4096;
66 
67 // variables
68 
69 static bool Init;
70 extern unsigned int HashSize;
71 pthread_mutex_t adapter_init_mutex;
72 pthread_cond_t adapter_init_cond;
73 
74 // prototypes
75 
76 static void parse_option ();
77 static bool parse_line   (char line[], char * * name_ptr, char * * value_ptr);
78 
79 static void stop_search  ();
80 
81 // functions
82 
83 // main()
84 
main_adapter(int argc,char * argv[])85 int main_adapter(int argc, char * argv[]) {
86 
87    // init
88 
89    Init = false;
90 
91    if (BlockSignal) {
92       signal(SIGINT,SIG_IGN);
93       signal(SIGTERM,SIG_IGN);
94       signal(SIGPIPE,SIG_IGN);
95    }
96 
97    util_init();
98 
99    option_init();
100 
101    square_init();
102    piece_init();
103    attack_init();
104 
105    hash_init();
106 
107    my_random_init();
108 
109    // build book
110 
111    if (argc >= 2 && my_string_equal(argv[1],"make-book")) {
112       book_make(argc,argv);
113       return EXIT_SUCCESS;
114    }
115 
116    if (argc >= 2 && my_string_equal(argv[1],"merge-book")) {
117       book_merge(argc,argv);
118       return EXIT_SUCCESS;
119    }
120 
121    // read options
122 
123    if (argc == 2) option_set("OptionFile",argv[1]); // HACK for compatibility
124 
125    parse_option(); // HACK: also launches the engine
126 
127    // EPD test
128 
129    if (argc >= 2 && my_string_equal(argv[1],"epd-test")) {
130       epd_test(argc,argv);
131       return EXIT_SUCCESS;
132    }
133 
134    // opening book
135 
136    book_clear();
137    if (option_get_bool("Book")) {
138       int mode = BookReadOnly;
139       if (option_get_bool("BookLearn")) {
140          mode = BookReadWrite;
141       }
142       book_open(option_get_string("BookFile"),mode);
143    }
144 
145    // flag adapter initialized
146    pthread_mutex_lock( &adapter_init_mutex );
147    pthread_cond_signal( &adapter_init_cond );
148    pthread_mutex_unlock( &adapter_init_mutex );
149 
150    // adapter
151    adapter_loop();
152 
153    engine_send(Engine,"quit");
154    engine_close(Engine);
155 
156    return EXIT_SUCCESS;
157 }
158 
159 // parse_option()
160 
parse_option()161 static void parse_option() {
162 
163    const char * file_name;
164    FILE * file;
165    char line[256];
166    char * name, * value;
167 
168    file_name = option_get_string("OptionFile");
169 
170    file = fopen(file_name,"r");
171    if (file == NULL) my_fatal( "Can't open file \"%s\": %s - using defaults\n",file_name,strerror(errno));
172 
173    // PolyGlot options (assumed first)
174 
175    if ( file != NULL ) {
176       while (true) {
177 
178          if (!my_file_read_line(file,line,256)) {
179             my_fatal("parse_option(): missing [Engine] section\n");
180          }
181 
182          if (my_string_case_equal(line,"[engine]")) break;
183 
184          if (parse_line(line,&name,&value)) option_set(name,value);
185       }
186    }
187 
188    if (option_get_bool("Log")) {
189       my_log_open(option_get_string("LogFile"));
190    }
191 
192    my_log("POLYGLOT *** START ***\n");
193    my_log("POLYGLOT INI file \"%s\"\n",file_name);
194 
195    // engine options (assumed second and last)
196 
197    engine_open(Engine);
198    Init = true; // engine has been launched
199    uci_open(Uci,Engine);
200 
201    if ( file != NULL ) {
202       while (my_file_read_line(file,line,256)) {
203 
204          if (line[0] == '[') my_fatal("parse_option(): unknown section %s\n",line);
205 
206          if (parse_line(line,&name,&value)) {
207             if ( strcmp(name,"Hash") == 0 ) {
208                sscanf( value, "%d", &HashSize );
209             }
210             uci_send_option(Uci,name,"%s",value);
211          }
212       }
213    }
214 
215    uci_send_isready(Uci);
216 
217    if ( file != NULL ) {
218       fclose(file);
219    }
220 
221    if (my_string_equal(option_get_string("EngineName"),"<empty>")) {
222       option_set("EngineName",Uci->name);
223    }
224 }
225 
226 // parse_line()
227 
parse_line(char line[],char ** name_ptr,char ** value_ptr)228 static bool parse_line(char line[], char * * name_ptr, char * * value_ptr) {
229 
230    char * ptr;
231    char * name, * value;
232 
233    ASSERT(line!=NULL);
234    ASSERT(name_ptr!=NULL);
235    ASSERT(value_ptr!=NULL);
236 
237    // remove comments
238 
239    ptr = strchr(line,';');
240    if (ptr != NULL) *ptr = '\0';
241 
242    ptr = strchr(line,'#');
243    if (ptr != NULL) *ptr = '\0';
244 
245    // split at '='
246 
247    ptr = strchr(line,'=');
248    if (ptr == NULL) return false;
249 
250    name = line;
251    value = ptr+1;
252 
253    // cleanup name
254 
255    while (*name == ' ') name++; // remove leading spaces
256 
257    while (ptr > name && ptr[-1] == ' ') ptr--; // remove trailing spaces
258    *ptr = '\0';
259 
260    if (*name == '\0') return false;
261 
262    // cleanup value
263 
264    ptr = &value[strlen(value)]; // pointer to string terminator
265 
266    while (*value == ' ') value++; // remove leading spaces
267 
268    while (ptr > value && ptr[-1] == ' ') ptr--; // remove trailing spaces
269    *ptr = '\0';
270 
271    if (*value == '\0') return false;
272 
273    // end
274 
275    *name_ptr = name;
276    *value_ptr = value;
277 
278    return true;
279 }
280 
281 // quit()
282 
quit()283 void quit() {
284 
285    char string[StringSize];
286 
287    my_log("POLYGLOT *** QUIT ***\n");
288 
289    if (Init) {
290 
291       stop_search();
292       engine_send(Engine,"quit");
293 
294       pthread_exit(NULL);
295 
296       // wait for the engine to quit
297 
298       while (true) {
299          engine_get(Engine,string,StringSize); // HACK: calls exit() on receiving EOF
300       }
301 
302       uci_close(Uci);
303    }
304 
305    //exit(EXIT_SUCCESS);
306 }
307 
308 // stop_search()
309 
stop_search()310 static void stop_search() {
311 
312    if (Init && Uci->searching) {
313 
314       ASSERT(Uci->searching);
315       ASSERT(Uci->pending_nb>=1);
316 
317       my_log("POLYGLOT STOP SEARCH\n");
318 
319 /*
320       engine_send(Engine,"stop");
321       Uci->searching = false;
322 */
323 
324       if (option_get_bool("SyncStop")) {
325          uci_send_stop_sync(Uci);
326       } else {
327          uci_send_stop(Uci);
328       }
329    }
330 }
331 
332 }  // namespace adapter
333 
334 // end of main.cpp
335