1 #include "phalanx.h"
2 
3 #undef SHOWREADS
4 #undef SHOWDUPS
5 
6 tsbook Sbook;
7 tpbook Pbook;
8 
9 int Bookout=0;
10 
11 /*
12  *	myfwrite(), myfread() to fix the endianess problem.
13  */
14 
15 #	define ISI ((int)sizeof(int))
16 
myfwrite(void * ptr,int size,FILE * stream)17 void myfwrite( void *ptr, int size, FILE *stream )
18 {
19 	int i,j;
20 	for( i=0; i<size-ISI; i+=ISI )
21 	{ for( j=0; j!=ISI; j++ ) fwrite( (char*)ptr+i+j, 1, 1, stream ); }
22 	for( j=0; i+j<size; j++ ) fwrite( (char*)ptr+i+j, 1, 1, stream );
23 }
24 
myfread(void * ptr,int size,FILE * stream)25 void myfread(  void *ptr, int size, FILE *stream )
26 {
27 	int i,j;
28 	for( i=0; i<size-ISI; i+=ISI )
29 	{ for( j=0; j!=ISI; j++ ) fread( (char*)ptr+i+j, 1, 1, stream ); }
30 	for( j=0; i+j<size; j++ ) fread( (char*)ptr+i+j, 1, 1, stream );
31 }
32 
33 /*
34  *	write position into string s, to be saved in book or
35  *	compared with another position string.
36  *	Format: pieces as usual, black pieces by capital P,N,B,...
37  *	empty squares are stored as numbers, e.g. '24' means
38  *	24 empty sq.
39  */
postr(char * s)40 void postr(char *s)
41 {
42 	int i, counter, lenght;
43 	const char P[14]=
44 	{'-','-','p','P','n','N','b','B','r','R','q','Q','k','K'};
45 
46 	sprintf( s, "%1X%1X", (Color==BLACK), G[Counter].castling & 0xF );
47 
48 	counter=0; lenght=2;
49 	for(i=A1;i!=H9;i++) if( B[i] && B[i] != 3 )
50 	{
51 		if(counter)
52 		{
53 			sprintf(&s[lenght],"%i",counter);
54 			if(counter>9) lenght++;
55 			lenght++; counter=0;
56 		}
57 		sprintf(&s[lenght],"%c",P[B[i]/8+(color(B[i])==BLACK)]);
58 		lenght++;
59 	}
60 	else if( B[i]==0 ) counter++;
61 
62 	if(counter) sprintf(&s[lenght],"%i ",counter);
63 	else sprintf(&s[lenght]," ");
64 }
65 
66 
67 
68 
69 /*
70  *	Compare position strings p1 and p2.
71  *	p1==p2 ... returns 0
72  *	p1>p2 ... 1; p1<p2 ... -1
73  */
poscmp(char * p1,char * p2)74 int poscmp(char *p1, char *p2)
75 {
76 	register int i;
77 	for(i=0; i!=80; i++)
78 	{
79 		if(p1[i]=='\0') p1[i]=' ';
80 		if(p2[i]=='\0') p2[i]=' ';
81 
82 		if(p1[i]<p2[i]) return -1;
83 		if(p1[i]>p2[i]) return  1;
84 		if(p1[i]==' ') return 0;
85 	}
86 	fprintf(stderr,"Phalanx error: Opening book corrupted.\n");
87 	exit(2);
88 }
89 
90 
91 
92 /*
93  *	Now the book searching functions.  If there is less than
94  *	512 bytes to search, the book is searched linearly.
95  */
linSB(FILE * f,long from,long to,char * p,char * s)96 int linSB(FILE *f, long from, long to, char *p, char *s)
97 {
98 	if( fseek(f,from,SEEK_SET)!=0 ) { return -1; }
99 	if(!feof(f)) fgets(s,80,f);	/* skip to the first \n */
100 
101 	while(ftell(f)<=to && !feof(f))
102 	{
103 		fgets(s,100,f);
104 		if( poscmp(p,s)==0 ) return 0;
105 	}
106 
107 	return -1;
108 }
109 
110 
111 
112 /*
113  *	There is more than 512 bytes to search -> use binary search.
114  */
binSB(FILE * f,long from,long to,char * p,char * s)115 int binSB(FILE *f, long from, long to, char *p, char *s)
116 {
117 	long mid;
118 
119 	if( to-from < 512 ) return( linSB(f,from,to,p,s) );
120 
121 	mid=(to+from)/2;
122 	if( fseek(f,mid,SEEK_SET)!=0 ) return -1;
123 	if(!feof(f)) fgets(s,80,f);	/* skip to the first \n */
124 
125 	if(!feof(f)) fgets(s,100,f);
126 
127 	switch(poscmp(p,s))
128 	{
129 		case  0: return(0);
130 		case  1: return( binSB(f,mid,to,p,s) );
131 		case -1: return( binSB(f,from,mid,p,s) );
132 		default: return -1;
133 	}
134 }
135 
136 
137 
parsemove(char * inp,tmove * m,int n)138 int parsemove( char *inp, tmove *m, int n )
139 {
140 	int special, from, to, in2a, i;
141 
142 	special = 0;
143 	from = inp[0]-'a'+1 + 10*(inp[1]-'1') + 20;
144 	to =   inp[2]-'a'+1 + 10*(inp[3]-'1') + 20;
145 	in2a = 0;
146 
147 	if(    strncmp(inp,"o-o-o",5)==0
148 	    || strncmp(inp,"0-0-0",5)==0
149 	    || strncmp(inp,"O-O-O",5)==0
150 	    || ( B[E1]==WK && strncmp(inp,"e1c1",4)==0 )
151 	    || ( B[E8]==BK && strncmp(inp,"e8c8",4)==0 ) )
152 		special = LONG_CASTLING;
153 	else if(    strncmp(inp,"o-o",3)==0
154 	         || strncmp(inp,"0-0",3)==0
155 	         || strncmp(inp,"O-O",3)==0
156 	         || ( B[E1]==WK && strncmp(inp,"e1g1",4)==0 )
157 	         || ( B[E8]==BK && strncmp(inp,"e8g8",4)==0 ) )
158 		special = SHORT_CASTLING;
159 
160 	switch(inp[4])
161 	{
162 	case 'Q': case 'q': in2a=QUEEN+Color; break;
163 	case 'R': case 'r': in2a=ROOK+Color; break;
164 	case 'B': case 'b': in2a=BISHOP+Color; break;
165 	case 'N': case 'n': in2a=KNIGHT+Color; break;
166 	default : in2a=B[from];
167 	}
168 
169 	for(i=0; i!=n; i++)
170 	{
171 	if( ( special>0 && special<A1 && m[i].special == special ) ||
172 	    ( (m[i].from==from) && (m[i].to==to) && (m[i].in2a==in2a) )
173 	  ) return(i);
174 	}
175 
176 	return(-1);
177 }
178 
179 
180 
181 /* binary book */
sbookmoves(int * moves,int * values,tmove * m,int n)182 int sbookmoves( int *moves, int *values, tmove *m, int n )
183 {
184 	int idx, i;
185 	int64 first, last=0, middle=0;
186 	unsigned fkey, lkey;
187 	unsigned pos;
188 	long booksize; 	/* filesize in bytes */
189 	FILE *f;
190 	int hits=0;
191 
192 	if( (f=Sbook.f) == NULL ) return -1;
193 
194 	if( G[Counter].hashboard < Sbook.firstkey
195 	 || G[Counter].hashboard > Sbook.lastkey ) return -1;
196 
197 	fkey = Sbook.firstkey; lkey = Sbook.lastkey;
198 
199 	booksize = Sbook.filesize/6;
200 
201 	first = 0; last = booksize-1;
202 	if( G[Counter].hashboard == Sbook.firstkey ) middle=0;
203 	else if( G[Counter].hashboard == Sbook.lastkey ) middle=booksize-1;
204 	else
205 	while( first < last )
206 	{
207 		/* middle = (first+last) / 2; */
208 
209 		middle = (G[Counter].hashboard-fkey)*(last-first)
210 		       / (lkey-fkey) + first;
211 
212 		if(middle==first) middle++; if(middle==last) middle--;
213 		if(middle==first)
214 		{
215 #ifdef SHOWREADS
216 			printf("notfoundinbook %i\n", hits );
217 #endif
218 			return -1;
219 		}
220 
221 		if( fseek(f,middle*6,SEEK_SET)!=0 ) return -1;
222 		myfread( &pos, sizeof(unsigned), f ); hits++;
223 
224 		if( pos < G[Counter].hashboard ) { first=middle; fkey=pos; }
225 		else if( pos == G[Counter].hashboard ) break;
226 		else { last=middle; lkey=pos; }
227 	}
228 
229 /*
230 printf("[%i %i %i %i] [%08X %08X]\n",
231         first,middle,last,booksize,pos,G[Counter].hashboard);
232 */
233 
234 #ifdef SHOWREADS
235 	printf("yesfoundinbook %i\n",hits);
236 #endif
237 
238 	if( middle == 0 ) pos = G[Counter].hashboard;
239 	else
240 	do
241 	{
242 		middle --;
243 		if( fseek(f,middle*6,SEEK_SET)!=0 ) return -1;
244 		myfread( &pos, sizeof(unsigned), f );
245 	} while( middle>0 && pos==G[Counter].hashboard );
246 
247 	if(pos!=G[Counter].hashboard)
248 	{ middle ++; pos = G[Counter].hashboard; }
249 
250 	/*** Position found in book! ***/
251 	idx=0;
252 	if( fseek(f,middle*6+4,SEEK_SET)!=0 ) return -1;
253 	while( middle<booksize && pos==G[Counter].hashboard )
254 	{
255 		unsigned short sm;
256 
257 		myfread( &sm, sizeof(unsigned short), f );
258 		for( i=0; i!=n; i++ ) if( sm == smove(m+i) )
259 		{ moves[idx]=i; values[idx]=100; idx++; }
260 
261 		myfread( &pos, sizeof(unsigned), f );
262 	}
263 
264 	return idx;
265 }
266 
267 
268 
269 /*
270  *	bookmoves() returns number of moves found in book, or 0,
271  *	if no move is found.  moves[0],...,moves[index-1] are indexes
272  *	to the bookmoves in m[], n is numer of moves.  Moves must
273  *	be generated before.
274  */
bookmoves(int * moves,int * values,tmove * m,int n)275 int bookmoves( int *moves, int *values, tmove *m, int n )
276 {
277 	char s[256], p[256];
278 	int idx, i;
279 	long booksize; 	/* filesize in bytes */
280 	FILE *f;
281 
282 	if( (f=Pbook.f) == NULL ) return -1;
283 
284 	booksize = Pbook.filesize;
285 
286 	postr(p);	/* Current position to string */
287 	if( binSB(f,0,booksize,p,s) == -1 )
288 	{ return -1; }
289 
290 	/*** Position found in book! ***/
291 	idx=0;
292 	for(i=0; s[i]!='\n'; i++)
293 	{
294 		int pm;
295 		while(s[i]!=' ' && s[i]!='\n')
296 		{
297 			if(s[i]=='!' && idx) values[idx-1]+=100;
298 			i++;
299 		}
300 		if(s[i]=='\n') break; i++; if(s[i]=='\n') break;
301 		if( (pm=parsemove(&s[i],m,n)) != -1 )
302 		{ moves[idx]=pm; values[idx]=100; idx++; }
303 	}
304 
305 	return idx;
306 }
307 
308 
309 
310 /*
311  *	This function returns index of a random move found in book
312  *	or -1, if no move was found.  Moves must be generated.
313  */
bookmove(tmove * m,int n)314 int bookmove( tmove *m, int n )
315 {
316 	int moves[80], values[80], idx;
317 	int foundtxt=0;
318 
319 	idx = bookmoves(moves,values,m,n);
320 	if( idx <= 0 ) idx = sbookmoves(moves,values,m,n);
321 	else
322 	{
323 #ifdef SHOWDUPS
324 		int moves2[80]; int values2[80], idx2;
325 		idx2 = sbookmoves(moves2,values,m,n);
326 		if( idx2>=1 && idx>=1 && Counter>8 )
327 		{
328 			char p[256]; int i;
329 			postr(p);
330 			puts("found in both sbook and pbook");
331 			printboard(NULL);
332 			puts(p);
333 			printf("   0      0       0      0  book2 ");
334 			for( i=0; i!=idx2; i++ )
335 			if( i==0 || moves2[i-1]!=moves2[i] )
336 			{ printm( m[moves2[i]], NULL ); }
337 			puts("");
338 		}
339 #endif
340 		foundtxt=1;
341 	}
342 
343 	if( idx > 0 )
344 	{
345 		int ii, sumvalues=0, rn;
346 		for( ii=0; ii!=idx; ii++ )
347 		{ sumvalues += values[ii]; }
348 
349 		rn = rand()%sumvalues;
350 
351 		sumvalues = 0;
352 		for( ii=0; ii!=idx; ii++ )
353 		{ sumvalues += values[ii]; if( sumvalues >= rn ) break; }
354 
355 		if( Flag.post )
356 		{	int i;
357 			char s[128];
358 			if( Flag.xboard )
359 			sprintf(s,"  0      0     0        0  (");
360 			// sprintf(s,"   0      0       0      0  book");
361 			else
362 			sprintf(s,"Book moves ");
363 			for( i=0; i!=idx; i++ )
364 			{ printm( m[moves[i]], s+strlen(s) ); }
365 
366 			// hacked by S.A. to show bookX at end of line
367 			if( foundtxt ) sprintf(s+strlen(s),", book1)");
368 			else sprintf(s+strlen(s),", book2)");
369 
370 			sprintf(s+strlen(s),"\n");
371 			printf("%s",s);
372 			if( Flag.log!=NULL && Flag.ponder<2 )
373 			{
374 				char sm[64];
375 				if(Flag.xboard) fprintf(Flag.log,"%s",s+26);
376 				else            fprintf(Flag.log,"%s",s);
377 				fprintf(Flag.log,"  selected move ");
378 				printm( m[moves[ii]], sm );
379 				fprintf(Flag.log,"%s\n",sm);
380 			}
381 		}
382 		return ( moves[ii] );
383 	}
384 
385 	return( -1 );
386 }
387 
388 
389 
390 /*
391  *	Print all book moves (command bk)
392  */
393 FILE * Eco = NULL;
bk(tmove * m,int n)394 void bk( tmove *m, int n )
395 {
396 int moves[80], values[80], idx;
397 int pass;
398 int sumvalues=0;
399 
400 #define SHOWECO
401 #ifdef SHOWECO
402 static int att=1;
403 static int seco=0;
404 if( att != 0 && Eco!=NULL )
405 {
406 	typedef struct teco { unsigned hashboard; unsigned point; } teco;
407 	static struct teco * peco = NULL;
408 	if( att==1 && Counter==0 && G[Counter].hashboard==0x39512910 /*init*/)
409 	{
410 		int c; tmove * move;
411 		peco = malloc(2048*sizeof(teco));
412 		if( peco == NULL )
413 		{ puts(" telluser cannot alloc memory for ECO");
414 		  att=0; goto abort; }
415 
416 		printf("telluser creating ECO index, please wait\n");
417 
418 		while( (c=fgetc(Eco))!='[' ) if( c==EOF ) goto doneinit;
419 		for(;;)
420 		{
421 		  tmove m[128];
422 		  char ms[32]; int msi; int n;
423 		  (peco+seco)->point=ftell(Eco)-1;
424 		  while( (c=getc(Eco))!=']' ) if( c==EOF ) goto doneinit;
425 		  if( c==EOF ) goto doneinit;
426 		  setfen(initialpos);
427 		  for(;;)
428 		  {
429 		 	msi=0;
430 		  	while( (c=getc(Eco))==' ' || c=='\n' ) {}
431 			ungetc(c,Eco);
432 			while( (c=getc(Eco))!=' ' && c!='\n' && msi<=30 )
433 			{ ms[msi]=c; msi++;
434 			  if( c==EOF || c=='[' )
435 			  { ungetc(c,Eco); goto nextgame; }
436 			}
437 			ms[msi]='\0'; /* printf("%s ",ms); */
438 			generate_legal_moves( m, &n, checktest(Color) );
439 			move=sandex(ms,m,n);
440 			if( move==NULL ) goto nextgame;
441 			do_move(move);
442 		  	if( c==EOF ) goto doneinit;
443 		  }
444 		  nextgame:;
445 		  peco[seco].hashboard=G[Counter].hashboard;
446 		  seco++;
447 		  while( (c=fgetc(Eco))!='[' ) if( c==EOF ) goto doneinit;
448 		}
449 
450 		doneinit:;
451 		printf(" parsed %i ECO records\n",seco);
452 		att=2;
453 		setfen(initialpos);
454 	}
455 
456 	if( Counter>0 && att>1 )
457 	{
458 		int counter=Counter;
459 		int text=-1;
460 		while( Counter > 0 )
461 		{
462 			int i;
463 			for(i=0;i!=seco;i++)
464 			if(peco[i].hashboard==G[Counter].hashboard)
465 			{ text=peco[i].point; goto foundeco; }
466 			undo_move( & G[Counter-1].m );
467 		}
468 		foundeco:;
469 		while( counter > Counter ) do_move( & G[Counter].m );
470 		if( text==-1 ) printf(" no eco found\n");
471 		else
472 		{ char t[128], * c;
473 		  fseek(Eco,text,SEEK_SET);
474 		  fgets(t,126,Eco);
475 		  t[127]='\0';
476 		  c=strchr(t,'['); if(c!=NULL) *c = ' ';
477 		  c=strrchr(t,']'); if(c!=NULL) *c = '\0';
478 		  puts(t);
479 		}
480 	}
481 	abort:;
482 }
483 #endif
484 
485 for( pass=0; pass!=2; pass++ )
486 {
487 	if( pass==0 )
488 	{
489 	int i;
490 	idx = bookmoves(moves,values,m,n);
491 	if( idx != -1 ) for(i=0;i!=idx;i++) sumvalues += values[i];
492 	printf(" primary book moves\n");
493 	}
494 	else
495 	{
496 	idx = sbookmoves(moves,values,m,n);
497 	printf(" secondary book moves\n");
498 	}
499 
500 	if( idx > 0 )
501 	{	int i;
502 		for( i=0; i!=idx; i++ )
503 		if( i==0 || moves[i-1]!=moves[i] )
504 		{
505 			printf("   ");
506 			printm( m[moves[i]], NULL );
507 			if(pass==0)
508 				printf("%3d%%\n",values[i]*100/sumvalues);
509 			else	printf("\n");
510 		}
511 	}
512 	else
513 	printf("   no move found\n");
514 
515 }
516 
517 if( Flag.xboard>1 ) puts("");
518 
519 { char c[128]; postr(c); printf("%s\n",c); }
520 
521 }
522 
523 
524