1 #include "phalanx.h"
2 #include "stdarg.h"
3 
4 extern long Time;
5 
6 
7 char Inp[256] = "\0";
8 char piece[7] =
9  { ' ', 'P', 'N', 'B', 'R', 'Q', 'K' };
10 char file[10] =
11  { '<', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', '>' };
12 char row[12] =
13  { '<', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '>' };
14 
15 tmove Pm[256];
16 int Pn;
17 
18 
19 
20 /*
21  * printf() wrapper that also records the messages to the logfile
22  * Phalanx logs the messages only if started with the -g <logfile> parameter
23  */
printfl(const char * format,...)24 int printfl( const char * format, ... )
25 {
26 va_list arg;
27 int done;
28 
29 va_start(arg,format);
30 done = vprintf( format, arg );
31 va_end(arg);
32 
33 if( Flag.log != NULL )
34 {
35 	fputc( '>', Flag.log );
36 	va_start(arg,format);
37 	vfprintf( Flag.log, format, arg );
38 	va_end(arg);
39 }
40 
41 return done;
42 }
43 
44 
45 
46 /**
47 *** Init board and structures
48 *** To be called after position is set (FEN or xboard's edit)
49 **/
initbs(void)50 void initbs(void)
51 {
52 
53 int s;
54 
55 Counter = 0;
56 DrawScore = 0;
57 
58 G[0].hashboard = hashboard();
59 
60 /* Do full material count */
61 G[0].mtrl = G[0].xmtrl = 0;
62 for( s=A1; s!=H9; s++ )
63   if( color(B[s]) == Color ) G[0].mtrl += Values[ B[s]>>4 ];
64   else G[0].xmtrl += Values[ B[s]>>4 ];
65 
66 /* busted! S.A.
67 G[0].castling = 0;
68 if( B[E1]!=WK || B[A1]!=WR ) G[0].castling |= WLONG;
69 if( B[E1]!=WK || B[H1]!=WR ) G[0].castling |= WSHORT;
70 if( B[E8]!=BK || B[A8]!=BR ) G[0].castling |= BLONG;
71 if( B[E8]!=BK || B[H8]!=BR ) G[0].castling |= BSHORT;
72 */
73 
74 G[0].rule50 = 0;
75 
76 /* create the piece list */
77 L[L[1].next].prev = 1;
78 L[L[2].next].prev = 2;
79 L[L[1].next].next = L[L[2].next].next = 0;
80 {
81 	int wlast = L[1].next, blast = L[2].next;
82 	for( s=A1; s!=H9; s++ )
83 	if( B[s]!=0 && B[s]!=3 && B[s]!=WK && B[s]!=BK )
84 	{
85 	if( color(B[s])==WHITE )
86 	{ L[wlast].next = s; L[s].prev = wlast; L[s].next = 0; wlast = s; }
87 	else
88 	{ L[blast].next = s; L[s].prev = blast; L[s].next = 0; blast = s; }
89 	}
90 }
91 
92 }
93 
94 
95 
96 /**
97 *** Xboard compatible edit
98 **/
edit(void)99 void edit(void)
100 {
101 int i;
102 int color = WHITE;
103 int squ, pie;
104 char s[8];
105 s[0] = '@';
106 
107 for(;;)
108 {
109 	for( i=0; i!=3; i++ ) s[i] = toupper((int)s[i]);
110 
111 	switch(*s)
112 	{
113 	case '#':
114 		for(i=A1;i!=H9;i++) if(B[i]!=3) B[i]=0;
115 	break;
116 	case 'C':
117 		color = enemy(color);
118 	break;
119 	case 'S':
120 		Color = enemy(Color);
121 	break;
122 	case '.': break;
123 	case 'P': case 'N': case 'B': case 'R': case 'Q': case 'K':
124 		squ = s[1]-'A' + 10*(s[2]-'1') + A1;
125 		if( squ<A1 || squ>H8 ) squ=0;
126 		pie = 0;
127 		for( i=1; i!=7; i++ ) if( s[0] == piece[i] )
128 		{ pie = i*16+color; break; }
129 		B[squ]=pie;
130 		if( *s == 'K' ) L[color].next = squ;
131 	break;
132 	}
133 
134 	printboard(NULL); printf("\n");
135 	printf("       <piece><location>\n");
136 	printf("       .            exit\n");
137 	printf("       #           clear\n");
138 	printf("       c          change          ");
139 	if( color==WHITE ) printf("put white pieces\n");
140 	else printf("put black pieces\n");
141 	printf("       s    side to move\n");
142 	printf("edit > ");
143 
144 	if( fgets(s,7,stdin) == NULL )
145 	{ strcpy(Inp,"quit\n"); return; }
146 
147 	if( *s == '.' ) break;
148 }
149 
150 initbs();
151 Inp[0]='\0'; return;
152 
153 }
154 
155 
156 
157 /**
158 *** Print move in full notation (Ng1-f3) to string 's' or to stdout.
159 *** SAN would be more complicated since we need a list of all possible
160 *** moves to find out whether to print 'Nbd2' or 'Nd2'.
161 **/
printm(tmove m,char * s)162 void printm( tmove m, char *s )
163 {
164 
165 char ss[64];
166 
167 switch( m.special )
168 {
169   case LONG_CASTLING:  sprintf( ss, "O-O-O  " ); goto endprint;
170   case SHORT_CASTLING: sprintf( ss, "O-O  " ); goto endprint;
171   case NULL_MOVE: sprintf( ss, "NULLMOV "); goto endprint;
172 }
173 
174 if( m.in1 != WP && m.in1 != BP ) sprintf( ss, "%c", piece[m.in1>>4] );
175 else ss[0]='\0';
176 
177 sprintf( ss+strlen(ss), "%c%c%c%c%c",
178 	file[m.from%10], row[m.from/10],
179 	( m.in2 || m.special ) ? 'x' : '-',
180 	file[m.to%10], row[m.to/10] );
181 
182 if( m.in2a != m.in1 ) sprintf( ss+strlen(ss), "%c", piece[m.in2a>>4] );
183 
184 #ifdef SHOW_FORCED_MOVES
185 if( m.dch != 100 ) sprintf( ss+strlen(ss), "/%i",m.dch );
186 #endif
187 
188 sprintf( ss+strlen(ss), "  " );
189 
190 endprint:;
191 
192 if( s == NULL ) printf("%s",ss); else strcpy( s, ss );
193 
194 }
195 
196 
197 
198 #ifdef SANOUT
199 
printmSAN(tmove * m,int i,int n,char * s)200 void printmSAN( tmove *m, int i, int n, char *s )
201 {
202 char ss[8];  /* longest: "Nb1xd2+\0" */
203 int j;
204 tmove *mi = m+i;
205 
206 switch( mi->special )
207 {
208   case LONG_CASTLING:  sprintf( ss, "O-O-O" ); goto endprint;
209   case SHORT_CASTLING: sprintf( ss, "O-O" ); goto endprint;
210   case NULL_MOVE: sprintf( ss, "NULLM"); goto endprint;
211 }
212 
213 if( piece(mi->in1) == PAWN )
214 {
215 	sprintf( ss, "%c", file[mi->from%10] );
216 	if( mi->in2 != 0 || mi->special )
217 		sprintf( ss+strlen(ss),
218 			"x%c%c",
219 			file[mi->to%10], row[mi->to/10] );
220 	else sprintf( ss+strlen(ss), "%c", row[mi->to/10] );
221 	if( mi->in1 != mi->in2a )
222 		sprintf( ss+strlen(ss), "=%c", piece[mi->in2a>>4] );
223 	goto endprint;
224 }
225 
226 /* print NBRQ moves */
227 sprintf( ss, "%c", piece[mi->in1>>4] );
228 
229 for( j=0; j!=n; j++ )
230 if( j!=i && mi->in1 == m[j].in1 && mi->to == m[j].to
231  && mi->from%10 != m[j].from%10 )
232 	sprintf( ss+strlen(ss), "%c", file[mi->from%10] );
233 
234 for( j=0; j!=n; j++ )
235 if( j!=i && mi->in1 == m[j].in1 && mi->to == m[j].to
236  && mi->from%10 == m[j].from%10 )
237 	sprintf( ss+strlen(ss), "%c", row[mi->from/10] );
238 
239 if( mi->in2 != 0 || mi->special ) sprintf( ss+strlen(ss), "x" );
240 
241 sprintf( ss+strlen(ss), "%c%c", file[mi->to%10], row[mi->to/10] );
242 
243 endprint:;
244 
245 /* is this a checking move? */
246 do_move( m+i );
247 if( checktest(Color) ) sprintf( ss+strlen(ss), "+" );
248 undo_move( m+i );
249 
250 if( s == NULL ) printf(ss); else strcpy( s, ss );
251 
252 }
253 
254 
255 
pvSAN(tmove * v,char * s)256 void pvSAN( tmove *v, char *s )
257 {
258 int n;
259 tmove m[256];
260 int i;
261 
262 generate_legal_moves( m, &n, checktest(Color) );
263 
264 for( i=0; i!=n; i++ )
265 if( smove(v) == smove(m+i) ) break;
266 
267 if( i != n )
268 {
269 	printmSAN( m, i, n, s );
270 	do_move( m+i );
271 	v++;
272 	if( v->from )
273 	{
274 		sprintf( s+strlen(s), " " );
275 		pvSAN( v, s+strlen(s) );
276 	}
277 	undo_move( m+i );
278 }
279 
280 }
281 
282 #endif
283 
284 
285 
286 /* GNU Chess `X' understands only moves in `g1f3' notation. We have to send
287  * this to older versions of xboard when playing phalanx with gnu. */
gnuprintm(tmove m)288 void gnuprintm(tmove m)
289 {
290 
291 switch( m.special )
292 {
293   case LONG_CASTLING:  printf("O-O-O"); return;
294   case SHORT_CASTLING: printf("O-O"); return;
295 }
296 
297 printf( "%c%c%c%c",
298 	file[m.from%10], row[m.from/10],
299 	file[m.to%10], row[m.to/10] );
300 if ( m.in2a != m.in1 ) printf( "%c", tolower((int)piece[m.in2a>>4]) );
301 
302 }
303 
304 
305 
306 /**
307 *** Return pointer to move in m[] if it matches the SAN representation.
308 *** If there is no such move, return NULL.
309 **/
sandex(char * inp,tmove * m,int n)310 tmove * sandex( char *inp, tmove *m, int n )
311 {
312 	char bufik[32];
313 	char *s = bufik;
314 	char * ss; char * sto;
315 	int move,to;
316 	int i;
317 	unsigned p=0;
318 	int frow=0, ffile=0;
319 	int in2a=0;
320 	int color = color(m->in1);
321 	int sc=-1; int lc=-1;
322 
323 	strncpy(bufik,inp,30);
324 
325 	for( i=0; i!=n; i++ ) if(m[i].special==SHORT_CASTLING) sc=i;
326 	else if(m[i].special==LONG_CASTLING) lc=i;
327 
328 	/*** step 0: castlings ***/
329 	if( lc != -1 )
330 	if(  strncmp(s,"o-o-o",5)==0
331 	  || strncmp(s,"O-O-O",5)==0
332 	  || strncmp(s,"0-0-0",5)==0
333 	  || ( strncmp(s,"e1c1",4)==0 && color==WHITE )
334 	  || ( strncmp(s,"e8c8",4)==0 && color==BLACK )
335 	  ) return m+lc;
336 
337 	if( sc != -1 && s[3]!='-' )
338 	if(  strncmp(s,"o-o",3)==0
339 	  || strncmp(s,"O-O",3)==0
340 	  || strncmp(s,"0-0",3)==0
341 	  || ( strncmp(s,"e1g1",4)==0 && color==WHITE )
342 	  || ( strncmp(s,"e8g8",4)==0 && color==BLACK )
343 	  ) return m+sc;
344 
345 	/*** step 1: noncastling move must start with PNBRQKabcdefgh ***/
346 	/***         if it starts with pnrqk, do the letter upercase ***/
347 	{
348 		static char ok[] = "PNBRQKabcdefghpnrqk";
349 		static char up[] = "pnrqk";
350 		for( i=0; ok[i]!=*s; i++ ) if( ok[i] == '\0' ) return(NULL);
351 		for( i=0; up[i]!='\0'; i++ )
352 			if( up[i] == *s ) { *s = toupper((int)*s); break; }
353 	}
354 
355 	/*** step 2: find the destination square ***/
356 	/* Find the last digit <1-8> in the input string.  It must
357 	 * be the row of the destination square and must be preceded
358 	 * by letter <a-h> of the dest. square **********************/
359 	sto=NULL;
360 	for( ss=s+1; *ss!='\0'; ss++ ) if( *ss>='1' && *ss<='8' ) sto = ss-1;
361 	if( sto == NULL )
362 	{
363 		if(    ( s[2]=='\0' || s[2]=='\n' )
364 		    && s[1]>='a' && s[1]<='h'
365 		    && s[0]>='a' && s[0]<='h' )
366 		{ /* exception: pawn capture can be typed as 'ef' */
367 			int mn=-1;
368 /* printf("trying exception %c %c %c\n", s[0], s[1], s[2] ); */
369 			for( i=0; i!=n; i++ )
370 				if( piece(m[i].in1) == PAWN )
371 					if( m[i].from%10 == s[0]+1-'a' )
372 						if( m[i].to%10 == s[1]+1-'a' )
373 						{
374 							if( mn==-1 )
375 								mn=i;
376 							else
377 								mn=-2;
378 						}
379 			if( mn>=0 ) return m+mn;
380 		}
381 		return NULL;  /* no digit 1-8 found */
382 	}
383 
384 	for( i=1; i!=9; i++ ) if(file[i]==*sto) break;
385 	if(i==9) return NULL;
386 	to = i;
387 	for( i=2; i!=10; i++ ) if(row[i]==sto[1]) break;
388 	if(i==10) return NULL;
389 	to += i*10;
390 
391 	/*** step 3: find the origin square ***/
392 	/* 3a - try to find full description of origin square (g1f3) */
393 	ss=sto-1;
394 	if(ss>=s)
395 	for( ss=sto-1; ss!=s; ss-- )
396 	if( *ss>='1' && *ss<='8' && *(ss-1)>='a' && *(ss-1)<='h' )
397 	{
398 		for( i=2; i!=10; i++ ) if(row[i]==*ss) break;
399 		frow = i;
400 		ss--; for( i=1; i!=9; i++ ) if(file[i]==*ss) break;
401 		ffile = i;
402 		for(i=0;i!=n;i++) if(m[i].from==frow*10+ffile)
403 		{ p=m[i].in1; break; }
404 		goto step4;
405 	}
406 	/* 3b - origin square must be computed from piece */
407 	{
408 		for(p=6;p!=1;p--) if( piece[p] == *s ) { s++; break; }
409 		p = (p<<4) + color;
410 		if( *s!='x' && s<sto ) /* init frow or ffile */
411 		{
412 			if( *s>='a' && *s<='h' ) ffile = *s-'a'+1;
413 			else
414 			if( *s>='1' && *s<='8' ) frow = *s-'1'+2;
415 		}
416 
417 	}
418 
419 	step4:;
420 	/*** step 4: is it a pawn promotion? determine piece ***/
421 	in2a = p;
422 	sto += 2; if( *sto == '=' ) sto++;
423 	*sto = toupper((int)*sto);
424 	for(i=2;i!=7;i++) if( piece[i]==*sto ) in2a=(i<<4)+color;
425 
426 	/*** step 5: scan move list ***/
427 	move = -1;
428 	for(i=0;i!=n;i++) if( m[i].to==to && m[i].in1==p && m[i].in2a==in2a )
429 	if( ffile==0 || ffile==m[i].from%10 )
430 	if( frow==0  ||  frow==m[i].from/10 )
431 	{ if(move==-1) move=i; else return NULL; }
432 	if(move==-1) return NULL;
433 
434 	return m+move;
435 }
436 
437 
438 
439 /**
440 *** Is the string represented move ("Pe2-e4") same as the tmove move?
441 *** This correctly parses almost anything but not SAN - we dont have
442 *** full move list.
443 **/
checkmove(char * s,tmove * m)444 int checkmove( char *s, tmove *m )
445 {
446 	int i;
447 
448 	if( m->special == LONG_CASTLING )
449 	{
450 		if( strncmp(s,"o-o-o",5)==0
451 		  || strncmp(s,"O-O-O",5)==0
452 		  || strncmp(s,"0-0-0",5)==0
453 		  || ( Color == WHITE && strncmp(s,"e1c1",4) == 0 )
454 		  || ( Color == BLACK && strncmp(s,"e8c8",4) == 0 )
455 		  ) return 1;
456 		else return 0;
457 	}
458 
459 	if( m->special == SHORT_CASTLING )
460 	{
461 		if(  ( strncmp(s,"o-o",3)==0 && strncmp(s,"o-o-o",5)!=0 )
462 		  || ( strncmp(s,"O-O",3)==0 && strncmp(s,"O-O-O",5)!=0 )
463 		  || ( strncmp(s,"0-0",3)==0 && strncmp(s,"0-0-0",5)!=0 )
464 		  || ( Color == WHITE && strncmp(s,"e1g1",4) == 0 )
465 		  || ( Color == BLACK && strncmp(s,"e8g8",4) == 0 )
466 		  ) return 1;
467 		else return 0;
468 	}
469 
470 	for( i=0; s[i]!='\0' && ! islower((int)s[i]); i++ );
471 	if( s[i]=='\0' || s[i]!=file[m->from%10] ) return 0;
472 
473 	i++;
474 	if( s[i]=='\0' || s[i]!=row[m->from/10] ) return 0;
475 
476 	for(    ; s[i]!='\0' && ( s[i]=='x' || ! islower((int)s[i]) ); i++ );
477 	if( s[i]=='\0' || s[i]!=file[m->to%10] ) return 0;
478 
479 	i++;
480 	if( s[i]=='\0' || s[i]!=row[m->to/10] ) return 0;
481 
482 	i++;
483 	if( m->in2a != m->in1 )
484 	{
485 		if( s[i] == '=' || s[i] == ':' ) i++;
486 		if( toupper((int)s[i]) != piece[m->in2a>>4] ) return 0;
487 	}
488 
489 	return 1;
490 }
491 
492 
493 
printPV(int mpl,int lid,char * s)494 void printPV( int mpl, int lid, char *s )
495 /* mpl ... moves per line */
496 {
497 	char ss[1024] = "";
498 	int j;
499 
500 #ifdef SHOW_FORCED_MOVES
501 	if( mpl>2 ) mpl -= 2;
502 #endif
503 
504 #ifdef SANOUT
505 	int k=0;
506 	int l=lid;
507 	char s1[1024] = "";
508 	pvSAN( PV[0], s1 );
509 	for( j=0; s1[j]!='\0'; j++,l++ )
510 	if( l <= 72 || s1[j] != ' ' ) { ss[k] = s1[j]; k++; }
511 	else
512 	{
513 		ss[k] = '\n'; k++;
514 		for( l=0; l!=lid; l++ ) { ss[k] = ' '; k++; }
515 	}
516 	ss[k] = '\0';
517 #else
518 	for(j=0;PV[0][j].from;j++)
519 	{
520 		if( j%mpl == 0 && j != 0 && Flag.xboard<2 )
521 		{
522 			int i;
523 			sprintf( ss+strlen(ss), "\n" );
524 			for( i=0; i!=lid; i++ ) sprintf( ss+strlen(ss), " " );
525 		}
526 		printm( PV[0][j], ss+strlen(ss) );
527 	}
528 
529 	if( j < 3 ) sprintf( ss+strlen(ss), "           " );
530 #endif
531 
532 	sprintf( ss+strlen(ss), "\n" );
533 
534 	if( s == NULL ) printf("%s",ss); else strcpy(s,ss);
535 }
536 
537 
538 
infoline(int typ,char * s)539 void infoline( int typ, char *s )
540 {
541 /** typ:
542 ***  0 ... search finished, summary information
543 ***  1 ... normal 'xboard' line, known eval, time, full PV
544 ***  2 ... '!' - turn, new best move
545 ***  3 ... summary informations at the end of ply level, no PV
546 ***  4 ... '??' - first move fails low
547 ***  5 ... '!!' - current move fails high, over window
548 **/
549 
550 char ss[1024];
551 extern long T1;
552 long t = ptime();
553 
554 if( typ!=0 && (typ!=3 || Flag.xboard<=1) && ( Abort || t-T1 < Flag.noise ) ) return;
555 
556 if( Flag.log && s==NULL )
557 {
558 	int x = Flag.xboard;
559 	Flag.xboard = 0;
560 	infoline(typ,ss);
561 	Flag.xboard = x;
562 	fprintf(Flag.log,"%s", ss);
563 }
564 
565 if( Flag.xboard > 1 )
566 switch( typ )
567 {	case 0: /* ICS whispering */
568 		if( Flag.ponder<2 && Flag.xboard>1 && typ==0 )
569 		{
570 		  printf(
571 "tellics whisper depth=%i; eval=%c%i.%02i; nodes=%lli; nps=%i\n",
572 A_d,
573 PV[0][0].value>=0 ? '+' : '-',
574 abs(PV[0][0].value/100),
575 abs(PV[0][0].value)%100,
576 Nodes,
577 (int)( ((float)Nodes) / (((float)max(t-T1,1))/100) ) );
578 /*
579 		  printPV(8,5,ss);
580 		  printf("tellics whisper %s",ss);
581 */
582 		}
583 	return;
584 	case 3: typ=1; break;
585 }
586 
587 if( typ >= 1 && typ <= 5 )
588 {
589 	sprintf( ss, "%3i", A_d );
590 	if( typ==1 || typ==2 || typ==4 || typ == 5 )
591 		sprintf( ss+strlen(ss), "%7i", PV[0][0].value );
592 	else if( typ == 3 ) sprintf( ss+strlen(ss), " -> " );
593 
594 	if( typ == 3 )
595 	{
596 		long tt = (long) (ptime()-T1);
597 		long t = tt / 100;
598 		sprintf( ss+strlen(ss), "%3i:%02i.%02li",
599 		        (int)t/60, (int)t%60, tt*100/100-t*100 );
600 	}
601 	else
602 	{
603 		sprintf( ss+strlen(ss), " %5li", (long)(t-T1) );
604 	}
605 	sprintf( ss+strlen(ss), " %8lli  ", Nodes );
606 }
607 else
608 {
609 	sprintf( ss,
610 		"Depth=%i, Value=%i, Time=%i.%02i, Last turn=%i.%02i, Nodes=%i",
611 		(int) A_d,
612 		(int) PV[0][0].value,
613 		(int) (t-T1)/100,
614 		(int) (t-T1)%100,
615 		(int) (LastTurn-T1)/100,
616 		(int) (LastTurn-T1)%100,
617 		(int) Nodes );
618 	if( t-T1 != 0 )
619 	sprintf( ss+strlen(ss), ", N/s=%i\n",
620 		(int)
621 		( (float) Nodes / ( (float)(t-T1)/(float)100 ) )
622 	      );
623 	else sprintf( ss+strlen(ss), "\n" );
624 }
625 
626 switch( typ )
627 {
628 case 0:
629 	sprintf( ss+strlen(ss), "PV = " ); printPV(8,5,ss+strlen(ss));
630 	if( PV[0][0].value > CHECKMATE-100 )
631 	sprintf( ss+strlen(ss),
632 		"     Mate in %i\n", (CHECKMATE-PV[0][0].value+1) / 2 );
633 break;
634 case 1: printPV(6,27,ss+strlen(ss));
635 break;
636 case 2:
637 	printm( PV[0][0], ss+strlen(ss) );
638 	sprintf( ss+strlen(ss), "!       \n" );
639 break;
640 case 3: sprintf( ss+strlen(ss), "%2i turn", Turns );
641 	if(Turns==1) sprintf( ss+strlen(ss), "                          \n");
642 	else         sprintf( ss+strlen(ss), "s                         \n");
643 break;
644 case 4: printm( PV[0][0], ss+strlen(ss) );
645 	sprintf( ss+strlen(ss), "??      \n" );
646 break;
647 case 5: printm( PV[0][0], ss+strlen(ss) );
648 	sprintf( ss+strlen(ss), "!!      \n" );
649 }
650 
651 if( s != NULL ) strcpy( s, ss );
652 else
653 {
654 	printf("%s",ss);
655 }
656 
657 }
658 
659 
660 
verboseline(void)661 void verboseline( void )
662 {
663 	char s[256];
664 	int j;
665 	extern long T1;
666 	long t = (long) (ptime()-T1);
667 
668 	if( Flag.xboard==0 )
669 	{
670 		t /= 100; /* seconds elapsed */
671 		sprintf( s, "(%2i)", A_d );
672 		sprintf( s+strlen(s), "   ");
673 		sprintf( s+strlen(s), "%3li:%02li   ", t/60, t%60 );
674 		sprintf( s+strlen(s), "%9lli  ", Nodes );
675 		sprintf( s+strlen(s), "(%2i/%2i) ", A_i+1, A_n );
676 		printm( A_m[A_i], s+strlen(s) );
677 		sprintf( s+strlen(s), "     " );
678 		for( j=0; j!=79; j++ ) sprintf( s+strlen(s), "" );
679 		printf("%s",s);
680 	}
681 	else
682 	{
683 		sprintf( s, "stat01: %li %li %i %i %i ",
684 		                 t, /* time elapsed in centiseconds */
685 		                     (long) Nodes,
686 		                         A_d, /* A_d breaks Arena */
687 		                            A_n - A_i - 1,
688 		                               A_n
689 		);
690 		printf("%s",s);
691 		gnuprintm(A_m[A_i]); puts("");
692 	}
693 }
694 
695 
696 
printboard(char * s)697 void printboard(char *s)
698 {
699 	int i;
700 	char ss[2048];
701 
702 	sprintf(ss, "  +---+---+---+---+---+---+---+---+\n  ");
703 	for(i=A8;i>=A1;i++)
704 	{
705 		switch(color(B[i]))
706 		{
707 		case WHITE:
708 			sprintf(ss+strlen(ss),"| %c ",piece[B[i]>>4]);
709 		break;
710 		case BLACK:
711 			sprintf(ss+strlen(ss),"| *%c",piece[B[i]>>4]);
712 		break;
713 		default: sprintf(ss+strlen(ss),"|   ");
714 		}
715 		if( i%10 == 8 )
716 		{
717 			i-=18;
718 			sprintf(ss+strlen(ss),
719 				"|\n  +---+---+---+---+---+---+---+---+");
720 			if(i!=10) sprintf(ss+strlen(ss),"\n  ");
721 		}
722 	}
723 	if( Color == WHITE ) sprintf(ss+strlen(ss),"   White to move\n");
724 	else sprintf(ss+strlen(ss),"   Black to move\n");
725 
726 	if( s==NULL ) printf("%s",ss); else strcpy(s,ss);
727 
728 	/* printf("%08X\n",G[Counter].hashboard); */
729 }
730 
731 
732 
733 /**
734 ***  The setfen() function is one of the two ways to set a position.
735 ***  The second one is edit().
736 **/
setfen(const char * f)737 int setfen( const char *f )
738 {
739 const char *g, *errmsg, errstring[] = "tellusererror Illegal position";
740 int i,j;
741 tgamenode p, q;
742 
743    if( Flag.log != NULL )
744    {
745      fprintf(Flag.log,"\n\nsetting position\n%s\n\n",f);
746    }
747    if (Flag.xboard > 0)
748       errmsg = errstring;
749    else  /* interactive mode */
750       errmsg = strchr(errstring, ' ') + 1; /* skip "tellusererror" */
751 
752    memset(B, 3, sizeof(B));
753    for (i=FILE_A; i<=FILE_H; i++)
754        memset(&B[10*i+11], 0, 8);
755    memset(G, 0, sizeof(G));
756    p = q = G[0];
757 
758    for (j = A8; j != H1+1; f++)
759    {
760       if(*f == '\0' || *f == ' ') /* we shall find info for each squares */
761       { puts(errmsg); return 1; }
762 
763       if (isdigit((int)*f)) /* skip a number of squares */
764       {
765          if (*f == '0' || *f == '9') /* these are not allowed */
766          { puts(errmsg); return 1; }
767          j += (*f-'0');
768       }
769       else if (*f == '/')  /* end of row reached, go to next row */
770       {
771          if (j%10 == 9)
772             j -= 18;  /* next lower row */
773          else
774          { puts(errmsg); return 1; } /* we are lacking a field in the row processed */
775       }
776       else
777       {
778          switch( tolower((int)*f) )
779          {
780          case 'k': B[j] = KING;   break;
781          case 'q': B[j] = QUEEN;  break;
782          case 'r': B[j] = ROOK;   break;
783          case 'b': B[j] = BISHOP; break;
784          case 'n': B[j] = KNIGHT; break;
785          case 'p': B[j] = PAWN;   break;
786          default: puts(errmsg); return 1;  /* illegal piece char */
787          }
788          if (tolower((int)*f) == (int)*f) /* black */
789             B[j] |= BLACK;
790          else
791             B[j] |= WHITE;
792          if (piece(B[j]) == KING)
793             L[color(B[j])].next=j;
794          j++;
795       }
796    }
797 
798    while (*f == ' ' && *f != '\0')
799       f++;
800    switch(*f)
801    {
802      case 'w': Color = WHITE; break;
803      case 'b': Color = BLACK; break;
804      default: puts(errmsg); return 1;
805    }
806    f++;
807 /* set up castling */
808    while (*f == ' ' && *f != '\0')
809       f++;
810    q.castling = 0;
811    if (strchr(f, 'K')==NULL)     /* no K */
812       q.castling |= WSHORT;   /* white short castling is impossible */
813    if (strchr(f, 'Q')==NULL)     /* no Q */
814       q.castling |= WLONG;    /* white long castling is impossible */
815    if (strchr(f, 'k')==NULL)     /* no k */
816       q.castling |= BSHORT;   /* black short castling is impossible */
817    if (strchr(f, 'q')==NULL)     /* no q */
818       q.castling |= BLONG;    /* black long castling is impossible */
819 
820    while (*f != ' ' && *f != '\0')
821       f++;
822    while (*f == ' ' && *f != '\0')
823       f++;
824 
825 /* en-passant */
826    g = f + 1;
827    if (  *f != '-'
828       && strchr("abcdefgh", *f) != NULL
829       && (  (*g == '3' && Color == BLACK)
830          || (*g == '6' && Color == WHITE)
831          )
832       )
833    {  /* en-passant is possible so the last move was a pawn move
834          which we construct here */
835       /* determine the target field i */
836       i = 21 + (int)(*f-'a') + 10*(int)(*g-'1');
837       j = 10;
838       if (Color == WHITE)
839          j = -j;
840       /* piece was an opposite pawn, obviously,
841        * so check if this is plausible */
842       if (B[i+j] == (PAWN | (Color ^ (BLACK|WHITE))))
843       {  /* to and from are one line before and after the special field */
844          p.m.from    = i - j;
845          p.m.special = i;
846          p.m.to      = i + j;
847          p.m.in1     = p.m.in2a = B[i+j];
848       }
849       f = g + 1;   // jump behind the e.p. info
850    }
851    while (*f != ' ' && *f != '\0')
852       f++;
853    while (*f == ' ' && *f != '\0')
854       f++;
855 
856    initbs();
857    q.hashboard = hashboard();
858    q.mtrl = p.xmtrl = G[0].mtrl;
859    q.xmtrl = p.mtrl = G[0].xmtrl;
860    G[0].mtrl = G[0].xmtrl = G[0].hashboard = 0;
861 
862    /* Now we should have the fifty-move info */
863    i = 0;
864    while (isdigit((int)*f) && f != '\0') /* find the end of the fifty-move info */
865       i = 10*i + (*f - '0'), f++;
866    q.rule50 = i < 50 ? i : 50;
867    if (i > 0 && p.m.special != 0) /* we have a "previous" move because of e.p. */
868       p.rule50 = q.rule50 - 1; /* so set the rule50 info, too, can't be wrong */
869 
870    while (*f == ' ' && *f != '\0')
871       f++;
872 
873    /* Finally, check the fullmove number */
874    Counter = 0;
875 
876 #undef nodef /* this block breaks moves/time timecontrols, Counter must be 0 */
877 #ifdef nodef
878    if (p.m.special != 0)
879    {
880       Counter++;
881       if (Color == WHITE)
882          Counter++;
883    }
884 
885    i = 0;
886    while (isdigit((int)*f) && *f != '\0') /* find the end of the fullmove number */
887       i = 10*i + (*f - '0'), f++;
888    i = 2*i;
889    if (i != 0)
890    {
891       i--;
892       if (Color == BLACK)
893          i++;
894       Counter = i;
895    }
896 #endif
897 
898    /* put results in place */
899    G[Counter] = q;
900    if (Counter > 0 && p.m.special != 0)
901       G[Counter-1] = p;
902    return 0;
903 }
904 
905 
906 
907 /**
908 *** If an entered string contains seven (or more) slashes
909 *** it is considered as fen test position.
910 **/
sevenslashes(register char * s)911 int sevenslashes(register char *s)
912 {
913 	register int n=7;
914 	while( *s!='\0' && *s!=' ' )
915 	{
916 		if(*s=='/') { n--; if(!n) return 1; }
917 		s++;
918 	}
919 	return 0;
920 }
921 
922 
923 
924 /**
925 *** Is the current position terminal?
926 *** returns: 0 ... not terminal
927 ***          1 ... draw, 50 moves or 3rd repetition; ok to continue play
928 ***          2 ... draw, stalemate
929 ***          3 ... checkmate
930 **/
terminal(void)931 int terminal(void)
932 {
933 
934 tmove m[256];
935 int n, c;
936 
937 generate_legal_moves( m, &n, c=checktest(Color) );
938 
939 if(!n) {
940 if(c) return 3;
941 else return 2;
942 }
943 if( G[Counter].rule50>=100 || repetition(2) || material_draw() )
944 { if(Flag.machine_color==(WHITE|BLACK)) Flag.machine_color=0;  return 1; }
945 
946 return 0;
947 
948 }
949 
950 
printpositionfen(void)951 void printpositionfen(void)
952 {
953 
954 int s, empty_counter=0, Castling=0;
955 
956 #define EMPTY_COUNTER if (empty_counter) { printf("%d", empty_counter); empty_counter=0; };
957 
958 for( s=A8; s>=A1; s++ )
959 {
960 	switch( B[s] )
961 	{
962 	case WK: EMPTY_COUNTER; printf("K"); break;
963 	case BK: EMPTY_COUNTER; printf("k"); break;
964 	case WQ: EMPTY_COUNTER; printf("Q"); break;
965 	case BQ: EMPTY_COUNTER; printf("q"); break;
966 	case WR: EMPTY_COUNTER; printf("R"); break;
967 	case BR: EMPTY_COUNTER; printf("r"); break;
968 	case WB: EMPTY_COUNTER; printf("B"); break;
969 	case BB: EMPTY_COUNTER; printf("b"); break;
970 	case WN: EMPTY_COUNTER; printf("N"); break;
971 	case BN: EMPTY_COUNTER; printf("n"); break;
972 	case WP: EMPTY_COUNTER; printf("P"); break;
973 	case BP: EMPTY_COUNTER; printf("p"); break;
974 
975         default: empty_counter++; break;
976 	}
977 
978 	if( s%10 == 8 )
979 	{
980 		EMPTY_COUNTER;
981 		s-=18;
982 		if (s!=H1-18) printf("/"); else printf(" ");
983 	}
984 }
985 
986 if( Color == WHITE ) printf("w "); else printf("b ");
987 
988 	/****** White Short ******/
989 	if( ( G[Counter].castling & WSHORT ) == 0 )
990 		{ printf("K"); Castling++;}
991 
992 	/****** White Long ******/
993 	if( ( G[Counter].castling & WLONG ) == 0 )
994                 { printf("Q"); Castling++;}
995 
996 	/****** Black Short ******/
997 	if( ( G[Counter].castling & BSHORT ) == 0 )
998                 { printf("k"); Castling++;}
999 	/****** Black Long ******/
1000 	if( ( G[Counter].castling & BLONG ) == 0 )
1001                 { printf("q"); Castling++;}
1002 
1003 if (!Castling) printf("- "); else printf(" ");
1004 
1005 if( Counter != 0 )
1006 {
1007 	int c = Counter-1;
1008 	if( piece(G[c].m.in1) == PAWN  &&  abs(G[c].m.from-G[c].m.to) == 20 )
1009 	/* The last move was a pawn double step */
1010 	{
1011 		int destination;
1012 		int special = G[c].m.to;
1013 
1014 		destination = Color==WHITE ? special+10 : special-10;
1015 		printf("%c%c ", file[destination%10], row[destination/10]);
1016 	}
1017 	else
1018 		printf("- ");
1019 }
1020 else printf("- ");
1021 
1022 printf("%d %d\n", G[Counter].rule50, Counter/2+1);
1023 
1024 }
1025 
about(void)1026 void about(void)
1027 {
1028 
1029 printf(" " ENGNAME " "); puts(VERSION);
1030 puts(" Copyright (C) Dusan Dobes, 1997-2000");
1031 
1032 printf(" Level ................. ");
1033 switch( Flag.level )
1034 {
1035 case averagetime:
1036 	printf( "average time %i seconds\n", Flag.centiseconds/100 );
1037 break;
1038 case timecontrol:
1039 	printf( "%i moves in %i minutes\n",
1040 	       Flag.moves, Flag.centiseconds/6000 );
1041 break;
1042 case fixeddepth:
1043 	printf( "%i search depth\n", Flag.depth/100 );
1044 break;
1045 case fixedtime:
1046 	printf( "fixed time %i seconds\n", Flag.centiseconds/100 );
1047 }
1048 
1049 printf(" Time .................. ");
1050 if( Flag.cpu ) puts("cpu"); else puts("elapsed");
1051 
1052 printf(" Book .................. ");
1053 if( Flag.book ) puts("on"); else puts("off");
1054 
1055 printf(" Learning .............. ");
1056 if( Flag.learn ) puts("on"); else puts("off");
1057 
1058 printf(" Permanent brain ....... ");
1059 switch( Flag.ponder )
1060 {	case 0: puts("off"); break;
1061 	case 1: puts("on"); break;
1062 	case 2: puts("on (pondering)"); break;
1063 	default:
1064 		break;
1065 		/* 2005-09-14, José de Paula
1066 		 * GCC 3.4 thinks that this "default:" without a
1067 		 * statement is an error, so I put a break here.
1068 		 */
1069 }
1070 
1071 printf(" Transposition table ... ");
1072 if( SizeHT == 0 ) puts("not used");
1073 else
1074 {
1075 	printf("hashing %i positions in %lu bytes\n",
1076 	SizeHT, (unsigned long)(sizeof(thashentry)*SizeHT) );
1077 }
1078 
1079 if( Flag.easy )
1080 {
1081 printf(" Easy level ............ %i\n",Flag.easy);
1082 }
1083 
1084 if( Flag.nps )
1085 {
1086 printf(" Nodes/second limit .... %i\n",Flag.nps);
1087 }
1088 
1089 printf(" Resigning ............. ");
1090 if( Flag.resign ) printf("%i.%02i\n",Flag.resign/100,Flag.resign%100);
1091 else printf("off\n");
1092 
1093 printf("\n");
1094 
1095 }
1096 
1097 
1098 
1099 /* SIG_INT handler */
interrupt(int x)1100 void interrupt(int x)
1101 {
1102 	int c;
1103 	signal(SIGINT,SIG_IGN);
1104 
1105 	if( Flag.polling )
1106 	{
1107 		/* ignore lines that begin with '.' */
1108 		c=getc(stdin); ungetc(c,stdin);
1109 		if( c=='.' )
1110 		{
1111 			fgets(Inp,255,stdin);
1112 			verboseline();
1113 			goto go_on;
1114 		}
1115 	}
1116 
1117 	if( Flag.ponder < 2 )
1118 	{
1119 		puts("interrupted");
1120 		Abort = 1;
1121 		goto go_on;
1122 	}
1123 	while( command() ) {}
1124 
1125 	go_on:;
1126 	if( !Abort && !Flag.polling ) signal(SIGINT,interrupt);
1127 }
1128 
1129 
1130 
command(void)1131 int command(void)
1132 {
1133 	static int no_prompt = 0;
1134 
1135 	if( Flag.xboard < 2 )
1136 	{
1137 		if( no_prompt )
1138 		{
1139 			no_prompt = 0;
1140 		}
1141 		else
1142 		if( Flag.ponder >= 2 )
1143 		{
1144 			printf("\n[ pondering ]\n");
1145 		}
1146 		else
1147 		{
1148 			printf( "[ %s, %i ]\n", Color==WHITE ? "white" : "black", Counter/2+1 );
1149 		}
1150 	}
1151 
1152 	if( Inp[0] == '\0' )
1153 	{
1154 		if( fgets(Inp,255,stdin) == NULL ) strcpy(Inp,"quit\n");
1155 		else if( Flag.log != NULL )
1156 			fprintf(Flag.log, "<%s", Inp);
1157 	}
1158 
1159 	if( strncmp(Inp,"exit",4) == 0 && Flag.analyze )
1160 	{ Flag.machine_color = Flag.analyze = 0; Inp[0]='\0'; return 1; }
1161 
1162 	if (  strncmp(Inp,"quit",4) == 0
1163 	   || strncmp(Inp,"exit",4) == 0
1164       )
1165 	{
1166 		if( Flag.ponder < 2 ) return 0;
1167 		else
1168 		{ Abort = 1; return 0; }
1169 	}
1170 
1171 /* COMMAND: protover */
1172 /* added by Bernhard Pruemmer, amended by DD */
1173 	if( strncmp( Inp, "protover", 8 ) == 0 )
1174 	{
1175 	   printfl("feature myname=\"" ENGNAME " " );
1176 	   if(Flag.easy)
1177 	   { printfl("Easy %i\"\n",Flag.easy); }
1178 	   else if(Flag.nps)
1179 	   { printfl("%i NPS\"\n",Flag.nps); }
1180 	   else printfl(VERSION"\"\n");
1181 
1182            printfl("feature analyze=1 "
1183            "setboard=1 "
1184            "sigint=1 "
1185            "time=1 "
1186            "memory=1 "
1187            "draw=0 "
1188 	   "option=\"Randomizer (0-50) -slider 0 0 50\" "
1189            "ping=1 \n"
1190            );
1191 	   printfl("feature done=1\n");
1192 	   Flag.xboard=20; /* version 2 */
1193 	   Inp[0]='\0'; return 1;
1194 	}
1195 
1196 
1197 /* COMMAND: comment */
1198 	if( Inp[0]=='#' )
1199 	{ printf("%s",Inp); no_prompt = 1; Inp[0]='\0'; return 1; }
1200 
1201 /* COMMAND: no op */
1202 	if( Inp[0]=='\n' )
1203 	{	Inp[0]='\0';
1204 		if( Flag.ponder >= 2 ) return 0; /* continue search */
1205 		else return 1;
1206 	}
1207 
1208 /* COMMAND: analyze */
1209 	if( strncmp( Inp, "analyze", 7 ) == 0 )
1210 	{
1211 		if( Flag.ponder >= 2 ) { Abort = 1; return 0; }
1212 		printfl("analyze mode, type 'exit' to terminate\n");
1213 		Flag.analyze = 1;
1214 		Flag.machine_color = 3;
1215 		Inp[0]='\0'; return 1;
1216 	}
1217 
1218 /* COMMAND: force */
1219 	if( strncmp( Inp, "force", 5 ) == 0 )
1220 	{
1221 		if( Flag.ponder >= 2 ) { Abort = 1; return 0; }
1222 		puts("you play both");
1223 		if( Flag.analyze ) Flag.machine_color = Color;
1224 		else Flag.machine_color = 0;
1225 		Inp[0]='\0'; return 1;
1226 	}
1227 
1228 /* COMMANDS: white, black */
1229 	if(  strncmp( Inp, "white", 5 ) == 0
1230 	  || strncmp( Inp, "black", 5 ) == 0 )
1231 	{
1232 		if( Flag.ponder >= 2 ) { Abort = 1; return 0; }
1233 		printfl("you do not play both\n");
1234 		if( Flag.machine_color == 0 )
1235 			Flag.machine_color = enemy(Color);
1236 		Inp[0]='\0'; return 1;
1237 	}
1238 
1239 /* COMMAND: both */
1240 	if( strncmp( Inp, "both", 4 ) == 0 )
1241 	{
1242 		if( Flag.ponder >= 2 ) { Abort = 1; return 0; }
1243 		printfl("machine plays both\n");
1244 		Flag.machine_color = 3;
1245 		Inp[0]='\0'; return 1;
1246 	}
1247 
1248 /* COMMAND: new */
1249 	if( strncmp( Inp, "new", 3 ) == 0 )
1250 	{
1251 		if( Flag.ponder >= 2 ) { Abort = 1; return 0; }
1252 		// setfen("rnbqkbnr/pppppppp/////PPPPPPPP/RNBQKBNR/w");
1253 		setfen(initialpos);
1254 		DrawScore = -10;
1255 		if( Flag.analyze ) Flag.machine_color = WHITE;
1256 		else
1257 		{
1258 			Flag.machine_color = BLACK;
1259 			puts("initial position set, machine plays black");
1260 		}
1261 		Inp[0]='\0'; return 1;
1262 	}
1263 
1264 /* COMMAND: go */
1265 	if( strncmp( Inp, "go", 2 ) == 0 )
1266 	{
1267 		if( Flag.ponder >= 2 ) { Abort = 1; return 0; }
1268 		Flag.machine_color = Color;
1269 		Inp[0]='\0'; return 1;
1270 	}
1271 
1272 /* COMMAND: bd */
1273 	if( strncmp( Inp, "bd", 2 ) == 0 || strncmp( Inp, "d\n", 2 ) == 0 )
1274 	{ printboard(NULL); Inp[0]='\0'; return 1; }
1275 
1276 /* COMMAND: bk */
1277 	if( strncmp( Inp, "bk", 2 ) == 0 )
1278 	{
1279 		tmove m[256]; int n;
1280 		extern void bk(tmove *, int );
1281 		if( Flag.ponder >= 2 ) { Abort = 1; return 0; }
1282 		generate_legal_moves( m, &n, checktest(Color) );
1283 		bk(m,n);
1284 /* printf("%08X\n",G[Counter].hashboard); */
1285 		Inp[0]='\0'; return 1;
1286 	}
1287 
1288 /* COMMAND: post */
1289 	if( strncmp( Inp, "post", 4 ) == 0 )
1290 	{
1291 		Flag.post = 1;
1292 		printfl("post on\n");
1293 		Inp[0]='\0'; return 1;
1294 	}
1295 
1296 /* COMMAND: nopost */
1297 	if( strncmp( Inp, "nopost", 6 ) == 0 )
1298 	{
1299 		Flag.post = 0;
1300 		printfl("post off\n");
1301 		Inp[0]='\0'; return 1;
1302 	}
1303 
1304 /* COMMAND: level */
1305 	if( strncmp( Inp, "level ", 6 ) == 0 )
1306 	{
1307 		l_level( Inp+6 );
1308 		Inp[0]='\0'; return 1;
1309 	}
1310 
1311 /* COMMAND: ping */
1312 	if( strncmp( Inp, "ping", 4 ) == 0 )
1313 	{
1314 		Inp[1]='o'; /* ping -> pong */
1315 		printfl(Inp);
1316 		Inp[0]='\0'; return 1;
1317 	}
1318 
1319 
1320 /* COMMAND: time */
1321 	if( strncmp( Inp, "time ", 5 ) == 0 )
1322 	{
1323 		sscanf( Inp+5, "%li", &Time );
1324 		Inp[0]='\0'; return 1;
1325 	}
1326 
1327 /* COMMAND: otim */
1328 	if( strncmp( Inp, "otim ", 5 ) == 0 )
1329 	{
1330 		sscanf( Inp+5, "%li", &Otim );
1331 		Inp[0]='\0'; return 1;
1332 	}
1333 
1334 /* COMMAND: rating <phalanx> <opponent> */
1335 	if( strncmp( Inp, "rating ", 7 ) == 0 )
1336 	{
1337 		int phal, oppo, diff;
1338 		if( sscanf( Inp+7, "%i %i", &phal, &oppo ) == 2 )
1339 		{
1340 			diff = oppo-phal;
1341 			if( diff > 300 ) DrawScore = 20;
1342 			else if( diff < -300 ) DrawScore = -20;
1343 			else DrawScore = diff/15;
1344 			printfl("setting draw score to %i\n",DrawScore);
1345 			Inp[0]='\0'; return 1;
1346 		}
1347 	}
1348 
1349 
1350 /* COMMAND: hard */
1351 	if( strncmp( Inp, "hard", 4 ) == 0 )
1352 	{
1353 		if( Flag.ponder==0 && Flag.easy==0 )
1354 		Flag.ponder = 1;
1355 		if(Flag.ponder) printfl("pondering on\n");
1356 		Inp[0]='\0'; return 1;
1357 	}
1358 
1359 /* COMMAND: easy */
1360 	if( strncmp( Inp, "easy", 4 ) == 0 )
1361 	{
1362 		if( Flag.ponder != 0 )
1363 		{
1364 			if( Flag.ponder >= 2 ) { Abort = 1; return 0; }
1365 			Flag.ponder = 0;
1366 		}
1367 		printfl("pondering off\n");
1368 		Inp[0]='\0'; return 1;
1369 	}
1370 
1371 /* COMMAND: beep, draw, ... ignored */
1372 	if(
1373 	    strncmp( Inp, "beep\n", 5 ) == 0
1374 	 || strncmp( Inp, "bogus\n", 6 ) == 0
1375 	 || strncmp( Inp, "draw\n", 5 ) == 0
1376 	 || strncmp( Inp, "name ", 5 ) == 0
1377 	 || strncmp( Inp, "random\n", 7 ) == 0
1378 	 || strncmp( Inp, "noise ", 6 ) == 0
1379 	 || strncmp( Inp, "result ", 7 ) == 0
1380 	 || strncmp( Inp, "accepted", 8 ) == 0
1381 	 || strncmp( Inp, "rejected", 8 ) == 0
1382 	 || strncmp( Inp, ".\n", 2 ) == 0
1383 	 || strncmp( Inp, "?\n", 2 ) == 0
1384 	)
1385 	{ /* ignore */ Inp[0]='\0'; return 1; }
1386 
1387 /* COMMAND: depth */
1388 	if( strncmp( Inp, "depth", 5 ) == 0 )
1389 	{
1390 		int newdepth;
1391 		if( Inp[5] == '\n' )
1392 		{ printf("depth= "); scanf( "%i", &newdepth ); }
1393 		else
1394 		{ sscanf( &Inp[6],"%i",&newdepth); }
1395 		Flag.depth = 100*newdepth;
1396 		if( Flag.depth < 200 ) Flag.depth = 200;
1397 		else if( Flag.depth > MAXPLY*100 ) Flag.depth = MAXPLY*100;
1398 		Flag.level = fixeddepth;
1399 
1400 		printfl("search depth %i\n", Flag.depth/100 );
1401 		Inp[0]='\0'; return 1;
1402 	}
1403 
1404 /* COMMAND: randomizer option N */
1405 	if( strncmp( Inp, "option Randomizer (0-50)=", 18 ) == 0 )
1406 	{
1407 		sscanf( &Inp[25],"%i",&Flag.random);
1408 		if( Flag.random )
1409 			printfl("telluser randomizer set to %i centipawns\n",
1410 			Flag.random);
1411 		else
1412 			printfl("telluser randomizer off\n");
1413 	}
1414 
1415 /* COMMAND: memory N */
1416 	if( strncmp( Inp, "memory", 6 ) == 0 )
1417 	{
1418 		int newsize;
1419 		thashentry * newHT;
1420 
1421 		if( Inp[6] == '\n' )
1422 		{ printf("memory in MB> "); scanf( "%i", &newsize ); }
1423 		else
1424 		{ sscanf( &Inp[7],"%i",&newsize); }
1425 /*
1426 printf("telluser Phalanx hashtable %i MB, ", newsize );
1427 */
1428 		if( newsize == 1 )
1429 			/* 1 MB requested, we use small HT */
1430 			newsize = 70000;
1431 		else
1432 		{
1433 			if( newsize <= 0 ) newsize = 0;
1434 			else /* newsize >= 2MB */
1435 			/* memory is in megabytes. we substract one megabyte
1436 			 * for other data structures */
1437 			newsize = ((newsize-1)*(1024*1024))/sizeof(thashentry);
1438 		}
1439 /*
1440 printf("%i entries\n",newsize);
1441 */
1442 		if( newsize == 0 )
1443 		{
1444 			free(HT);
1445 			SizeHT=0; HT=NULL;
1446 		}
1447 		else
1448 		{
1449 			newHT = realloc( HT, newsize*sizeof(thashentry) );
1450 			if( newHT != NULL )
1451 			{
1452 				HT = newHT; SizeHT = newsize;
1453 				memset( HT, 0, SizeHT*sizeof(thashentry) );
1454 			}
1455 		}
1456 		Inp[0]='\0'; return 1;
1457 	}
1458 
1459 /* COMMAND: book */
1460 	if( strncmp( Inp, "book", 4 ) == 0 )
1461 	{
1462 		Flag.book = ! Flag.book;
1463 		if( Flag.book ) printfl("book on\n");
1464 		else printfl("book off\n");
1465 		Inp[0]='\0'; return 1;
1466 	}
1467 
1468 /* COMMAND: about */
1469 	if( strncmp( Inp, "about", 5 ) == 0 )
1470 	{ about(); Inp[0]='\0'; return 1; }
1471 
1472 /* COMMAND: fen */
1473 	if( strncmp( Inp, "fen", 3 ) == 0 )
1474 	{ printpositionfen(); Inp[0]='\0'; return 1; }
1475 
1476 /* COMMAND: help */
1477 	if( strncmp( Inp, "help", 4 ) == 0 )
1478 	{
1479 puts("COMMAND SUMMARY: about (shows settings), bd (displays position - same");
1480 puts("as 'd'), bk (shows book info), book (enables/disables book), both");
1481 puts("(machine plays both), depth <N> (set search depth), fen, force (user");
1482 puts("plays both, go (start computing), help, history (show game moves),");
1483 puts("level <moves> <minutes> <increment in seconds>, level <seconds per");
1484 puts("move>, new (new game), post (show thinking), remove (take back last");
1485 puts("move, two plies), nopost (do not show thinking), quit (same as 'exit'");
1486 puts("or end of file character), score (show static evaluation), time <N>");
1487 puts("(remaining time is N/100 s), undo (undo last ply - same as 'u'),");
1488 puts("<FEN position> (set test position, start search, show result),");
1489 puts("# (comment)");
1490 		Inp[0]='\0'; return 1;
1491 	}
1492 
1493 /* COMMAND: score */
1494 	if( strncmp(Inp,"score\n",6) == 0 || strncmp(Inp,"s\n",2) == 0 )
1495 	{
1496 		Totmat = G[Counter].mtrl+G[Counter].xmtrl;
1497 		Scoring = 1; Depth = 100;
1498 		printf("\n (stm) material = %i\n",
1499 			G[Counter].mtrl-G[Counter].xmtrl);
1500 		printf(" TOTAL EVALUATION = %i\n",
1501 			score_position() );
1502 		printf("Wknow.hung=%i; Wknow.khung=%i\n",
1503 		        Wknow.hung, Wknow.khung);
1504 		printf("Bknow.hung=%i; Bknow.khung=%i\n",
1505 		        Bknow.hung, Bknow.khung);
1506 		puts("");
1507 		Scoring = 0;
1508 		Inp[0]='\0'; return 1;
1509 	}
1510 
1511 /* COMMAND: xboard */
1512 	if( strncmp( Inp, "xboard", 6 ) == 0 )
1513 	{
1514 		Flag.xboard = 2;
1515 		puts("xboard mode on");
1516 		Inp[0]='\0'; return 1;
1517 	}
1518 
1519 /* COMMAND: history */
1520 	if( strncmp( Inp, "history\n", 8 ) == 0 )
1521 	{
1522 		int i;
1523 		int sc = (Counter+Color+1) % 2;
1524 		if( sc ) printf("\n 1. ... ");
1525 		for( i=0; i<Counter; i++ )
1526 		{
1527 			if( (i+sc)%2 == 0 )
1528 			{
1529 				if( (i+sc)%6 == 0 ) puts("");
1530 				printf( "%2i. ", (i+sc+2)/2 );
1531 			}
1532 			printm( G[i].m, NULL );
1533 		}
1534 		puts("");
1535 		Inp[0]='\0'; return 1;
1536 	}
1537 
1538 /* COMMAND: undo (xboard) */
1539 	if( strncmp( Inp, "undo", 4 ) == 0 || strncmp( Inp, "u\n", 2 ) == 0 )
1540 	{
1541 		if( Flag.ponder >= 2 ) { Abort = 1; return 0; }
1542 		if( Counter != 0 )
1543 		{
1544 			undo_move( & G[Counter-1].m );
1545 			if(Flag.xboard<2) puts("halfmove back");
1546 			if( Flag.machine_color != 0 )
1547 			Flag.machine_color = enemy(Color);
1548 			if( Flag.analyze ) Flag.machine_color = Color;
1549 		}
1550 		else puts("cannot undo");
1551 		Inp[0]='\0'; return 1;
1552 	}
1553 
1554 /* COMMAND: remove (xboard) */
1555 	if( strncmp( Inp, "remove", 6 ) == 0 )
1556 	{
1557 		if( Flag.ponder >= 2 ) { Abort = 1; return 0; }
1558 		if( Counter > 1 )
1559 		{
1560 			undo_move( & G[Counter-1].m );
1561 			undo_move( & G[Counter-1].m );
1562 			if(Flag.xboard<2) puts("move back");
1563 			if( Flag.machine_color != 0 )
1564 			Flag.machine_color = enemy(Color);
1565 		}
1566 		else puts("cannot remove");
1567 		Inp[0]='\0'; return 1;
1568 	}
1569 
1570 /* COMMAND: setboard <FEN> */
1571 /* added by Pascal Georges */
1572 	if( strncmp( Inp, "setboard ", 9 ) == 0 )
1573 	{
1574 		if (setfen(Inp+9))
1575                    setfen(initialpos);
1576 		if(Flag.analyze) Flag.machine_color=3;
1577 		Inp[0] = '\0';
1578 		return 1;
1579 	}
1580 
1581 /* COMMAND: st <SECONDS> */
1582 /* added by stevenaaus */
1583 	if( strncmp( Inp, "st ", 3 ) == 0 )
1584 	{
1585 	  float seconds;
1586 	  if( sscanf(Inp+3,"%f",&seconds) == 0 ) {
1587 	    // expected a time in seconds
1588 	    printfl ("Error: \"st:\" expected float , but got %s\n", Inp+3);
1589 	  }
1590 	  // time argv S.A.
1591 	  printfl ("Setting average time to %f seconds\n",seconds);
1592 	  Flag.centiseconds = (int)(100*seconds);
1593 	  Flag.level = averagetime;
1594 	  Inp[0] = '\0';
1595 	  return 1;
1596 	}
1597 
1598 /* COMMAND: test a position */
1599 	if( sevenslashes(Inp) ) /* test */
1600 	{
1601 		if( Flag.ponder >= 2 ) { Abort = 1; return 0; }
1602 		if( setfen(Inp) == 0 )
1603 		{
1604 			static int entered=0;
1605 			static int found=0;
1606 			int f=0;
1607 			tmove m;
1608 			int i;
1609 
1610 			memset( HT, 0, SizeHT*sizeof(thashentry) );
1611 			printf("\n%s",Inp);
1612 			m = root_search();
1613 			Flag.machine_color = 0;
1614 			if( ! Flag.post ) { Depth += 100; infoline(0,NULL); }
1615 
1616 			entered++;
1617 			for( i=0; Inp[i]!='\0'; i++ )
1618 			if( checkmove( Inp+i, &m ) ) { f=1; found++; break; }
1619 
1620 			if( f ) printf("[ Solution correct    ");
1621 			else
1622 			{	FILE * nf; /* not found */
1623 				static char filename[16] = "notfound.fin";
1624 				if( entered-found == 1 )
1625 					nf = fopen(filename,"w");
1626 				else	nf = fopen(filename,"a");
1627 				if( nf != NULL )
1628 				{
1629 					fputs( Inp, nf );
1630 					fclose(nf);
1631 				}
1632 				printf("[ Solution incorrect  ");
1633 			}
1634 
1635 			printf(" %i.%02i%%, %i/%i ]\n",
1636 				found*100/entered,
1637 				found*10000/entered%100,
1638 				found,
1639 				entered);
1640 
1641 			no_prompt = 1;
1642 		}
1643 		Inp[0]='\0'; return 1;
1644 	}
1645 
1646 	/* suppose this is an user move */
1647 	if( Flag.ponder >= 2 )
1648 	{
1649 		tmove *pm = sandex(Inp,Pm,Pn);
1650 
1651 		if(pm!=NULL)
1652 		if(  pm->from == Pondermove.from
1653 		  && pm->to == Pondermove.to
1654 		  && pm->in1 == Pondermove.in1
1655 		  && pm->in2 == Pondermove.in2
1656 		  && pm->in2a == Pondermove.in2a
1657 		  && pm->special == Pondermove.special )
1658 		{
1659 			Flag.ponder = 1;
1660 			if( ! l_iterate() ) Abort = 2;
1661 			else
1662 			if( !Flag.polling ) signal(SIGINT,interrupt);
1663 			Inp[0] = '\0'; return 0;
1664 		}
1665 		Abort = 1; return 0;
1666 	}
1667 
1668 	if( terminal() < 2 )
1669 	{
1670 		tmove m[256]; int n; int i;
1671 		generate_legal_moves( m, &n, checktest(Color) );
1672 		{ tmove *sd = sandex(Inp,m,n); if(sd!=NULL) i=sd-m; else i=n; }
1673 		if( i != n )
1674 		{
1675 			if( Flag.xboard < 2 )
1676 			{
1677 				printf("\nyour move is ");
1678 				printm( m[i], NULL ); puts("");
1679 			}
1680 			do_move( m+i );
1681 			switch( terminal() )
1682 			{
1683 				case 1: printfl("1/2-1/2 {Drawn game}\n"); break;
1684 				case 2: printfl("1/2-1/2 {Stalemate}\n"); break;
1685 				case 3:
1686 					if( Color == WHITE )
1687 					printfl("0-1 {Black mates}\n");
1688 					else
1689 					printfl("1-0 {White mates}\n");
1690 			}
1691 			Inp[0]='\0'; return 1;
1692 		}
1693 	}
1694 
1695 	/*** UNKNOWN COMMAND / ILLEGAL MOVE ***/
1696 
1697 	{ char *c=strchr(Inp,'\n'); if(c!=NULL) *c='\0'; else *Inp='\0'; }
1698 	printfl("Illegal move: %s\n",Inp);
1699 	Inp[0] = '\0';
1700 
1701 	return 1;
1702 }
1703 
1704 
1705 
shell(void)1706 void shell(void)
1707 {
1708 
1709 while( command() )
1710 {
1711 	while( ( Flag.machine_color & Color ) && terminal() < 2 )
1712 	{
1713 		tmove m;
1714 		m = root_search();
1715 
1716 		if( Flag.analyze )
1717 		{ undo_move(&m); Flag.machine_color = enemy(Color); continue; }
1718 
1719 		if( Flag.ponder >= 2 )
1720 		{
1721 			Flag.ponder = 1;
1722 			undo_move(&m);
1723 			undo_move(&Pondermove);
1724 			continue;
1725 		}
1726 
1727 		if( Flag.machine_color == 3 && Abort == 1 )
1728 			Flag.machine_color = 0;
1729 
1730 		{
1731 			int ter;
1732 
1733 			if( Flag.resign != 0 )
1734 			{
1735 				static int resign=0;
1736 
1737 				if( m.value < -Flag.resign && Counter > 20 )
1738 				resign++; else resign=0;
1739 
1740 				if( resign > 3
1741 				 && Otim > 2000  /* oppo must have 20 s */
1742 				 && Otim + Flag.increment*900 > 9000
1743 /*				 && m.value > -CHECKMATE+100	*/
1744 				)
1745 				{
1746 					if( Flag.xboard>0 )
1747 						puts("tellics resign");
1748 					if( Color == WHITE )
1749 						puts("1-0 {Black resigns}");
1750 					else	puts("0-1 {White resigns}");
1751 				}
1752 			}
1753 
1754 			if( Flag.xboard < 2 )
1755 			{
1756 				printf("my move is "); printm( m, NULL ); puts("");
1757 			}
1758 			if( Flag.xboard > 0 )
1759 			{
1760 				printf("move "); gnuprintm(m); puts("");
1761 			}
1762 
1763 			switch( ( ter = terminal() ) )
1764 			{
1765 				case 1: puts("1/2-1/2 {Drawn game}"); continue;
1766 				case 2: puts("1/2-1/2 {Stalemate}"); continue;
1767 				case 3:
1768 					if( Color == WHITE )
1769 					puts("0-1 {Black mates}");
1770 					else
1771 					puts("1-0 {White mates}");
1772 				continue;
1773 			}
1774 
1775 			if(   Flag.ponder == 1
1776 			   && Flag.machine_color != 3
1777 			   && ter < 2
1778 			   && ( Abort != 0 || Abort != 4 ) )
1779 			{
1780 				int i;
1781 				Pondermove = PV[0][1];
1782 				generate_legal_moves(Pm,&Pn,checktest(Color));
1783 
1784 				for( i=0; i!=Pn; i++ )
1785 				if(  Pondermove.from == Pm[i].from
1786 				  && Pondermove.to == Pm[i].to
1787 				  && Pondermove.in1 == Pm[i].in1
1788 				  && Pondermove.in2a == Pm[i].in2a ) break;
1789 
1790 				if( i==Pn && Flag.nps==0 )
1791 				{
1792 					if( Flag.post )
1793 					{
1794 					puts("No move to ponder from PV.");
1795 					puts("Looking for a move to ponder.");
1796 					}
1797 
1798 					if( Bookout < 4 || Counter < 10 )
1799 						i = bookmove( Pm, Pn );
1800 					else
1801 						i = -1;
1802 
1803 					if( i != -1 )
1804 					{
1805 						Pondermove = Pm[i];
1806 						if( Flag.post )
1807 						puts("Found in book.");
1808 					}
1809 					else
1810 					{
1811 						if( Flag.post )
1812 						puts("Trying search.");
1813 					Depth = -100;
1814 					NoAbort = 1;
1815 					Ply = 1;
1816 					search(Pm,Pn,-CHECKMATE,CHECKMATE);
1817 					NoAbort = 0;
1818 					Pondermove = PV[1][1];
1819 					}
1820 					for( i=0; i!=Pn; i++ )
1821 					if(  Pondermove.from == Pm[i].from
1822 					  && Pondermove.to == Pm[i].to
1823 					  && Pondermove.in1 == Pm[i].in1
1824 					  && Pondermove.in2a == Pm[i].in2a )
1825 						break;
1826 					if( i==Pn )
1827 					{ if(Flag.post)
1828 					  puts("No move found.  A bug?");
1829 					  i=0;
1830 					}
1831 					else
1832 					{ if(Flag.post) puts("Done."); }
1833 				}
1834 
1835 				if( i != Pn )
1836 				{	/* OK, the move was also found in just
1837 					 * generated list of moves, not only in
1838 					 * the PV (principal variation).  Let's
1839 					 * ponder then!!! ********************/
1840 					do_move(&Pondermove);
1841 					if( terminal() > 1 )
1842 					undo_move(&Pondermove);
1843 					else
1844 					{
1845 						if( Flag.post )
1846 						{
1847 							printf("Hint: ");
1848 							printm(Pondermove,NULL);
1849 							puts("");
1850 						}
1851 						Flag.ponder = 2;
1852 					}
1853 				}
1854 			}
1855 			continue;
1856 		}
1857 	}
1858 }
1859 }
1860 
1861