1
2 /*
3 * The main module:
4 * - Parsing command line parameters
5 * - benchmark
6 */
7
8 #include "phalanx.h"
9
10 const char initialpos[] = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
11
12 /* 2005-09-14, José de Paula
13 * GCC 3.0 deprecated multi-line strings, and, as of GCC 3.4, they are no longer supported.
14 */
badoptions(void)15 void badoptions(void)
16 {
17 printf("\n"
18 "Usage: phalanx [options] [<moves> <minutes> [<increment in seconds>]]\n"
19 " phalanx [options] [<seconds per move>]\n"
20 " phalanx bench\n"
21 " phalanx bcreate [options]\n"
22 "Options: -t <transposition table size in kilobytes>\n"
23 " -f <fixed search time in seconds>\n"
24 " -x <+/-> xboard mode on/off default: on\n"
25 " -p <+/-> permanent brain on/off default: off\n"
26 " -s <+/-> show thinking on/off default: off\n"
27 " -c <+/-> cpu time default: off\n"
28 " -o <+/-> polling input default: on\n"
29 " -b <+/-> opening book default: on\n"
30 " -r <resign value in centipawns> default: 0 (no resigning)\n"
31 " -e <easy level 0...100> default: 0 (best play)\n"
32 " -z <randomize moves by centipawns> default: 0 (best play)\n"
33 " -z <centipawns>:<move number limit>\n"
34 " -n <NPS limit, min limit is 100> default: no limit\n"
35 " -l <+/-> learning on/off default: on\n"
36 " -v print version and exit\n"
37 " -P <primary book directory>\n"
38 " -S <secondary book directory>\n"
39 " -L <learning file directory>\n"
40 " -g <log file name>\n"
41 "Examples: phalanx -c+ -s+ -o - -x- -f 60 -t4000\n"
42 " xboard -fcp \"phalanx -l+ -r800\"\n"
43 );
44 exit(0);
45 }
46
47
get_book_file(char * bookdir,char * env_variable,char * path,char * name,int mode)48 char *get_book_file(char *bookdir,char *env_variable,
49 char *path,char *name,int mode)
50 {
51 char file[256];
52 char *aux;
53
54 if(bookdir) /* Specified in options? */
55 path = bookdir;
56 else if((aux=getenv(env_variable))) /* In an environment variable? */
57 path = aux;
58 else if(!access(name,mode)) /* In the current directory? */
59 path = ".";
60 else /* Desperacy now, use compile time file. */
61 ;
62
63 #ifdef GNUFUN
64 snprintf(file,255,"%s/%s",path,name);
65 #else
66 sprintf(file,"%s/%s",path,name);
67 #endif
68 return strdup(file);
69 }
70
71
main(int argc,char ** argv)72 int main( int argc, char **argv )
73 {
74
75 int c;
76 clock_t t;
77 char *PbookDir,*SbookDir,*LbookDir,*EcoDir;
78
79 #ifdef GNUFUN
80 int indexptr;
81 struct option longopts[] = {
82 { "help", no_argument, NULL, '?' },
83 { "version", no_argument, NULL, 'v' },
84 { "trans-table-cells", required_argument, NULL, 'T' },
85 { "trans-table-bytes", required_argument, NULL, 't' },
86 { "fixed-search-time", required_argument, NULL, 'f' },
87 { "xboard-mode", no_argument, &Flag.xboard, 1 },
88 { "no-xboard-mode", no_argument, &Flag.xboard, 0 },
89 { "permanent-brain", no_argument, &Flag.ponder, 1 },
90 { "no-permanent-brain", no_argument, &Flag.ponder, 0 },
91 { "show-thinking", no_argument, &Flag.post, 0 },
92 { "no-show-thinking", no_argument, &Flag.post, 1 },
93 { "cpu-time", no_argument, &Flag.cpu, 1 },
94 { "no-cpu-time", no_argument, &Flag.cpu, 0 },
95 { "poll-input", no_argument, &Flag.polling, 1 },
96 { "no-poll-input", no_argument, &Flag.polling, 0 },
97 { "use-opening-book", no_argument, &Flag.book, 1 },
98 { "no-use-opening-book", no_argument, &Flag.book, 0 },
99 { "easy-level", required_argument, NULL, 'e' },
100 { "resign-value", required_argument, NULL, 'r' },
101 { "learning", no_argument, &Flag.learn, 1 },
102 { "no-learning", no_argument, &Flag.learn, 0 },
103 { "primary-book-dir", required_argument, NULL, 'P' },
104 { "secondary-book-dir", required_argument, NULL, 'S' },
105 { "learning-file-dir", required_argument, NULL, 'L' },
106 { "log-file-name", required_argument, NULL, 'g' },
107 { 0,0,0,0 }
108 };
109 #endif
110
111 t = clock();
112
113 /* Do NOT buffer I/O - needed for communication with xboard */
114 setvbuf(stdout, (char*)NULL, _IONBF, 0);
115
116 printf("Phalanx "); puts(VERSION);
117
118 if(argc>1) if( strncmp("bcreate\0",argv[1],8) == 0 )
119 { return bcreate(argc-1,argv+1); }
120
121 /* Initialize the random number generator. */
122 srand( ((unsigned)time(NULL)) + ((unsigned)getpid()) );
123
124 /* SIG_INT */
125 signal(SIGINT,SIG_IGN);
126
127 setfen(initialpos);
128
129 #undef debugsee
130 #ifdef debugsee
131 {
132 int x; int j;
133 setfen("q2r2k1/1b3ppp/2prpn2/3P4/2PRP3/4NB2/5PPP/3R2K1 w");
134 printboard(NULL);
135 for(j=0;j!=1000000;j++) x=see(C6,D5);
136 printf(" [%i]\n",see(C6,D5));
137 return 0;
138 }
139 #endif
140
141 Flag.machine_color = BLACK;
142 Flag.post = 0;
143 Flag.analyze = 0;
144 Flag.xboard = 1;
145 Flag.book = 1;
146 Flag.centiseconds = 1000;
147 Flag.level = averagetime;
148 Flag.ponder = 0;
149 Flag.cpu = 0;
150 Flag.increment = 0;
151 Flag.polling = 1;
152 Flag.resign = 0;
153 Flag.nps = 0;
154 Flag.easy = 0;
155 Flag.random = 0;
156 Flag.rndlim = 0;
157 Flag.noise = 50; /* 0.5 s */
158 Flag.learn = 0;
159 Flag.bench = 0;
160 Flag.log = NULL;
161 Scoring = 0;
162
163 SbookDir = NULL;
164 PbookDir = NULL;
165 EcoDir = NULL;
166 LbookDir = NULL;
167
168 opterr = 0;
169
170 #ifdef GNUFUN
171 while( ( c = getopt_long( argc, argv, "vf:T:t:p:s:x:c:o:r:b:n:e:z:l:S:P:L:g:",
172 longopts, &indexptr) ) != -1 )
173 #else
174 while( ( c = getopt(argc,argv,"vf:T:t:p:s:x:c:o:r:b:n:e:z:l:S:P:L:g:") ) != -1 )
175 #endif
176 switch(c)
177 {
178 case 'T':
179 if( sscanf( optarg, "%i", &SizeHT ) == 0 ) badoptions();
180 break;
181 case 't':
182 if( sscanf( optarg, "%i", &SizeHT ) == 0 ) badoptions();
183 SizeHT = 1024 * SizeHT / sizeof(thashentry);
184 break;
185 case 'r': { int i;
186 if( sscanf( optarg, "%i", &i ) == 0 ) badoptions();
187 Flag.resign = abs(i); }
188 break;
189 case 'f':
190 {
191 static int t;
192 if( sscanf( optarg, "%i", &t ) == 0 ) badoptions();
193 Flag.centiseconds = t*100;
194 Flag.level = fixedtime;
195 } break;
196 case 'e':
197 {
198 static int e;
199 if( sscanf( optarg, "%i", &e ) == 0 ) badoptions();
200 if( e < 0 ) badoptions();
201 Flag.easy = e;
202 } break;
203 case 'z':
204 {
205 int r,rl=0;
206 if( sscanf( optarg, "%i:%i", &r, &rl ) == 0 )
207 badoptions();
208 if( r < 0 || rl<0 ) badoptions();
209 Flag.random = r;
210 Flag.rndlim = 2*rl;
211 } break;
212 case 'n':
213 {
214 int n;
215 if( sscanf( optarg, "%i", &n ) == 0 ) badoptions();
216 if( n < 100 ) badoptions();
217 Flag.nps = n;
218 } break;
219 case 'p': switch(*optarg)
220 { case '+': Flag.ponder = 1; break;
221 case '-': Flag.ponder = 0; break;
222 default: badoptions();
223 } break;
224 case 's': switch(*optarg)
225 { case '+': Flag.post = 1; break;
226 case '-': Flag.post = 0; break;
227 default: badoptions();
228 } break;
229 case 'x': switch(*optarg)
230 { case '+': Flag.xboard = 1; break;
231 case '-': Flag.xboard = 0; break;
232 default: badoptions();
233 } break;
234 case 'c': switch(*optarg)
235 { case '+': Flag.cpu = 1; break;
236 case '-': Flag.cpu = 0; break;
237 default: badoptions();
238 } break;
239 case 'o': switch(*optarg)
240 { case '+': Flag.polling = 1; break;
241 case '-': Flag.polling = 0; break;
242 default: badoptions();
243 } break;
244 case 'b': switch(*optarg)
245 { case '+': Flag.book = 1; break;
246 case '-': Flag.book = 0; break;
247 default: badoptions();
248 } break;
249 case 'l': switch(*optarg)
250 { case '+': Flag.learn = 1; break;
251 case '-': Flag.learn = 0; break;
252 default: badoptions();
253 } break;
254 case 'g':
255 {
256 if( ( Flag.log = fopen(optarg,"a") ) != NULL )
257 {
258 setvbuf(Flag.log, (char*)NULL, _IONBF, 0);
259 printf("log file %s\n",optarg);
260 }
261 else
262 printf("telluser Phalanx: cannot open log file\n");
263 } break;
264 case 'v': /* fprintf(stderr,"%s\n",VERSION); */ exit(0);
265 case 'P': PbookDir = strdup(optarg); break;
266 case 'E': EcoDir = strdup(optarg); break;
267 case 'S': SbookDir = strdup(optarg); break;
268 case 'L': LbookDir = strdup(optarg); break;
269 case '?':
270 badoptions();
271 break;
272 }
273
274 {
275 int m;
276 switch( argc - optind )
277 {
278 case 0: break;
279 case 1:
280 if( argc==2 && strncmp("bench\0",argv[1],6)==0 )
281 { Flag.bench = 1; break; }
282 if( sscanf(argv[optind],"%i",&m) == 0 ) badoptions();
283 Flag.centiseconds = 100*m;
284 Flag.level = averagetime;
285 break;
286 case 2:
287 if( sscanf(argv[optind],"%i",&m) == 0 ) badoptions();
288 Flag.moves = m;
289 if( sscanf(argv[optind+1],"%i",&m) == 0 ) badoptions();
290 Flag.centiseconds = m*6000;
291 Flag.level = timecontrol;
292 break;
293 case 3:
294 if( sscanf(argv[optind],"%i",&m) == 0 ) badoptions();
295 Flag.moves = m;
296 if( sscanf(argv[optind+1],"%i",&m) == 0 ) badoptions();
297 Flag.centiseconds = m*6000;
298 if( sscanf(argv[optind+2],"%i",&m) == 0 ) badoptions();
299 Flag.increment = m;
300 Flag.level = timecontrol;
301 break;
302 default: badoptions();
303 }
304 }
305
306 if( Flag.easy )
307 {
308 Flag.learn = 0; Flag.ponder = 0; SizeHT = 0;
309 if( Flag.nps==0 ) Flag.nps = 500 - 3*Flag.easy;
310 if( Flag.random==0 ) Flag.random = 10 + Flag.easy/2;
311 }
312
313 if( Flag.random ) Flag.learn=0;
314
315 if( Flag.nps && Flag.cpu )
316 {
317 Flag.cpu = 0;
318 printf("telluser ignored -c+, cannot be used with -n <nps>\n");
319 }
320
321 if( SizeHT != 0 )
322 {
323 HT = calloc( SizeHT, sizeof(thashentry) );
324 if( HT == NULL )
325 {
326 puts("cannot alloc hashtable"); SizeHT = 0;
327 }
328 }
329
330 /* alloc static eval cache */
331 { extern void initcache(void); initcache(); }
332
333 /* init distance tables */
334 { extern void initdist(void); initdist(); }
335
336 if( Flag.bench )
337 {
338 # define NPOS 10 /* number of positions */
339 int i;
340 long tim;
341 int64 allnodes = 0;
342 const char * positions[NPOS] =
343 { initialpos,
344 "2kr3r/pp3Npp/2pbbn2/6B1/2BPp3/6Pq/PPP1Q2P/2KR3R b",
345 "r1bq1r1k/2pn2bp/1p1p1np1/pN1Pp3/1PP1Pp2/P2B1P2/1BQN2PP/1R3RK1 b",
346 "r4rk1/2p1p1b1/p1n3pp/1p1qP3/P1pP4/B1P2PPN/4Q1K1/R6R b",
347 "8/1p3rpp/p2nk3/P3p3/2R5/2N2PP1/1P2K2P/8 w",
348 "rnbr2k1/ppq1ppbp/6p1/2p5/3P4/2PBPN2/P4PPP/1RBQ1RK1 w",
349 "3r1rk1/1q2b1pp/pn3p2/1pp5/4PB2/5N2/PP1RQPPP/3R2K1 w",
350 "8/2p5/5pK1/5R2/4k2P/p4P2/1r6/8 b",
351 "3r1rk1/p3qp1p/2bb2p1/2pp4/8/1P2P3/PBQN1PPP/2R2RK1 b",
352 "k7/ppp5/8/8/8/8/P1P5/K7 w"
353 };
354
355 Flag.cpu = 1;
356 Flag.level = fixedtime;
357 Flag.centiseconds = 3000;
358 Flag.post = Flag.book = Flag.learn = Flag.ponder = Flag.polling = 0;
359 printf("Running benchmark, this will take 5 minutes of CPU time.\n");
360 printf("----------");
361 tim = ptime();
362
363 for( i=0; i!=NPOS; i++ )
364 {
365 setfen(positions[i]);
366 if( i!=0 ) printf("+");
367 fflush(stdout);
368 root_search();
369 if( Abort == 1 ) return 0;
370 allnodes += Nodes;
371 }
372 printf("+\n%10i nodes per second\n",
373 (int)(100*allnodes / (ptime()-tim) ));
374
375 return 0;
376 }
377
378 /*** Opening book init ***/
379 /* Try to open book files. Give a message if not successful. */
380 SbookDir = get_book_file(SbookDir,ENV_SBOOK,SBOOK_DIR,SBOOK_FILE,R_OK);
381 Sbook.f = fopen(SbookDir,"rb");
382 PbookDir = get_book_file(PbookDir,ENV_PBOOK,PBOOK_DIR,PBOOK_FILE,R_OK);
383 Pbook.f = fopen(PbookDir,"rb");
384 EcoDir = get_book_file(EcoDir,ENV_ECO,ECO_DIR,ECO_FILE,R_OK);
385 Eco = fopen(EcoDir,"rb");
386 if( Flag.learn )
387 {
388 LbookDir
389 = get_book_file(LbookDir,ENV_LEARN,LEARN_DIR,LEARN_FILE,R_OK|W_OK);
390 Learn.f = fopen(LbookDir,"r+");
391 if( Learn.f == NULL )
392 {
393 # define LFSZ 65536
394 int b[LFSZ];
395 char filename[256];
396 memset( b, 0, LFSZ*sizeof(int) );
397 sprintf(filename,"./%s",LEARN_FILE);
398 free( LbookDir );
399 LbookDir = strdup( filename );
400 Learn.f = fopen(LbookDir,"w+");
401 if( fwrite( b, sizeof(int), LFSZ, Learn.f ) == LFSZ )
402 printf("telluser Phalanx: created learn file %s\n",LbookDir);
403 }
404 } else Learn.f = NULL;
405
406 if( Pbook.f != NULL )
407 {
408 struct stat fs;
409 stat(PbookDir,&fs); Pbook.filesize = fs.st_size;
410 printf("primary book %s, %d bytes\n",PbookDir,Pbook.filesize);
411 }
412
413 if( Sbook.f != NULL )
414 {
415 struct stat fs;
416 unsigned pos;
417 stat(SbookDir,&fs); Sbook.filesize = fs.st_size;
418 myfread( &pos, sizeof(unsigned), Sbook.f ); Sbook.firstkey=pos;
419 fseek( Sbook.f, Sbook.filesize-6, SEEK_SET );
420 myfread( &pos, sizeof(unsigned), Sbook.f ); Sbook.lastkey=pos;
421 printf("secondary book %s, %d bytes\n",SbookDir,Sbook.filesize);
422 }
423
424 if( Learn.f != NULL )
425 {
426 struct stat fs;
427 stat(LbookDir,&fs); Learn.filesize = fs.st_size;
428 printf("learning file %s, %d bytes\n",LbookDir,Learn.filesize);
429 }
430
431 if( Eco != NULL )
432 {
433 struct stat fs;
434 stat(EcoDir,&fs);
435 printf("eco file %s, %i bytes\n",EcoDir,(int) fs.st_size);
436 }
437
438 if( Sbook.f==NULL || Pbook.f==NULL )
439 { if( Flag.xboard ) printf("telluser Phalanx: ");
440 printf("Cannot open ");
441 }
442
443 if( Sbook.f == NULL )
444 if( Pbook.f == NULL )
445 printf("both [%s] and [%s]\n", SBOOK_FILE, PBOOK_FILE );
446 else
447 printf("[%s]\n", SBOOK_FILE );
448 else
449 if( Pbook.f == NULL )
450 printf("[%s]\n", PBOOK_FILE );
451
452 if( Learn.f == NULL && Flag.learn )
453 { Flag.learn=0; puts("telluser Phalanx: cannot open learn file"); }
454
455 printf("tellics set 1 Phalanx "); printf(VERSION);
456 if( Flag.easy || Flag.nps )
457 {
458 if( Flag.easy )
459 printf(", easy level %i", Flag.easy );
460 if( Flag.nps )
461 printf(", nodes per second limit = %i", Flag.nps );
462 printf("\n");
463 }
464 else
465 printf(", %i kB hashtable, %i/%i kB P/S opening book", (int)(((1+SizeHT)*sizeof(thashentry)-1)/1024),(int)(Pbook.filesize/1024), (int) (Sbook.filesize/1024));
466 printf("\n");
467
468 /************************************/
469 /************************************/
470 shell();
471 /************************************/
472 /************************************/
473
474 t = clock()-t;
475 printf("Processor time ......... %i:%02i:%02i.%02i\n",
476 (int) (t/CLOCKS_PER_SEC/3600),
477 (int) (t/CLOCKS_PER_SEC%3600/60),
478 (int) (t/CLOCKS_PER_SEC%60),
479 (int) (t*100/CLOCKS_PER_SEC%100) );
480
481 if( Age != 0 )
482 {
483 printf("Average search depth ... %g\n",
484 ((float)AllDepth) / ((float)(Age*100)) );
485 printf("Average NPS report ..... %g\n",
486 ((float)AllNPS) / ((float)Age) );
487 }
488
489 printf("Hash table age ......... %i\n", Age);
490
491 puts("Good bye!");
492
493 return 0;
494
495 }
496
497