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