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