#include "phalanx.h" extern long Time; char Inp[256] = "\0"; char piece[7] = { ' ', 'P', 'N', 'B', 'R', 'Q', 'K' }; char file[10] = { '<', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', '>' }; char row[12] = { '<', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '>' }; tmove Pm[256]; int Pn; /** *** Init board and structures *** To be called after position is set (FEN or xboard's edit) **/ void initbs(void) { int s; Counter = 0; DrawScore = 0; G[0].hashboard = hashboard(); /* Do full material count */ G[0].mtrl = G[0].xmtrl = 0; for( s=A1; s!=H9; s++ ) if( color(B[s]) == Color ) G[0].mtrl += Values[ B[s]>>4 ]; else G[0].xmtrl += Values[ B[s]>>4 ]; G[0].castling = 0; /* enabled all, disable if impossible: */ if( B[E1]!=WK || B[A1]!=WR ) G[0].castling |= WLONG; if( B[E1]!=WK || B[H1]!=WR ) G[0].castling |= WSHORT; if( B[E8]!=BK || B[A8]!=BR ) G[0].castling |= BLONG; if( B[E8]!=BK || B[H8]!=BR ) G[0].castling |= BSHORT; G[0].rule50 = 0; /* create the piece list */ L[L[1].next].prev = 1; L[L[2].next].prev = 2; L[L[1].next].next = L[L[2].next].next = 0; { int wlast = L[1].next, blast = L[2].next; for( s=A1; s!=H9; s++ ) if( B[s]!=0 && B[s]!=3 && B[s]!=WK && B[s]!=BK ) { if( color(B[s])==WHITE ) { L[wlast].next = s; L[s].prev = wlast; L[s].next = 0; wlast = s; } else { L[blast].next = s; L[s].prev = blast; L[s].next = 0; blast = s; } } } Flag.machine_color = enemy(Color); } /** *** Xboard compatible edit **/ void edit(void) { int i; int color = WHITE; int squ, pie; char s[8]; s[0] = '@'; for(;;) { for( i=0; i!=3; i++ ) s[i] = toupper(s[i]); switch(*s) { case '#': for(i=A1;i!=H9;i++) if(B[i]!=3) B[i]=0; break; case 'C': color = enemy(color); break; case 'S': Color = enemy(Color); break; case '.': break; case 'P': case 'N': case 'B': case 'R': case 'Q': case 'K': squ = s[1]-'A' + 10*(s[2]-'1') + A1; if( squH8 ) squ=0; pie = 0; for( i=1; i!=7; i++ ) if( s[0] == piece[i] ) { pie = i*16+color; break; } B[squ]=pie; if( *s == 'K' ) L[color].next = squ; break; } printboard(NULL); printf("\n"); printf(" \n"); printf(" . exit\n"); printf(" # clear\n"); printf(" c change "); if( color==WHITE ) printf("put white pieces\n"); else printf("put black pieces\n"); printf(" s side to move\n"); printf("edit > "); if( fgets(s,7,stdin) == NULL ) { strcpy(Inp,"quit\n"); return; } if( *s == '.' ) break; } initbs(); Inp[0]='\0'; return; } /** *** Print move in full notation (Ng1-f3) to string 's' or to stdout. *** SAN would be more complicated since we need a list of all possible *** moves to find out whether to print 'Nbd2' or 'Nd2'. **/ void printm( tmove m, char *s ) { char ss[64]; switch( m.special ) { case LONG_CASTLING: sprintf( ss, "O-O-O " ); goto endprint; case SHORT_CASTLING: sprintf( ss, "O-O " ); goto endprint; } sprintf( ss, "%c%c%c%c%c%c", piece[m.in1>>4], file[m.from%10], row[m.from/10], ( m.in2 || m.special ) ? 'x' : '-', file[m.to%10], row[m.to/10] ); if( m.in2a != m.in1 ) sprintf( ss+strlen(ss), "%c", piece[m.in2a>>4] ); #ifdef SHOW_FORCED_MOVES if( m.dch != 100 ) sprintf( ss+strlen(ss), "/%i",m.dch ); #endif sprintf( ss+strlen(ss), " " ); endprint:; if( s == NULL ) printf(ss); else strcpy( s, ss ); } #ifdef SANOUT void printmSAN( tmove *m, int i, int n, char *s ) { char ss[8]; /* longest: "Nb1xd2+\0" */ int j; tmove *mi = m+i; switch( mi->special ) { case LONG_CASTLING: sprintf( ss, "O-O-O" ); goto endprint; case SHORT_CASTLING: sprintf( ss, "O-O" ); goto endprint; } if( piece(mi->in1) == PAWN ) { sprintf( ss, "%c", file[mi->from%10] ); if( mi->in2 != 0 || mi->special ) sprintf( ss+strlen(ss), "x%c%c", file[mi->to%10], row[mi->to/10] ); else sprintf( ss+strlen(ss), "%c", row[mi->to/10] ); if( mi->in1 != mi->in2a ) sprintf( ss+strlen(ss), "=%c", piece[mi->in2a>>4] ); goto endprint; } /* print NBRQ moves */ sprintf( ss, "%c", piece[mi->in1>>4] ); for( j=0; j!=n; j++ ) if( j!=i && mi->in1 == m[j].in1 && mi->to == m[j].to && mi->from%10 != m[j].from%10 ) sprintf( ss+strlen(ss), "%c", file[mi->from%10] ); for( j=0; j!=n; j++ ) if( j!=i && mi->in1 == m[j].in1 && mi->to == m[j].to && mi->from%10 == m[j].from%10 ) sprintf( ss+strlen(ss), "%c", row[mi->from/10] ); if( mi->in2 != 0 || mi->special ) sprintf( ss+strlen(ss), "x" ); sprintf( ss+strlen(ss), "%c%c", file[mi->to%10], row[mi->to/10] ); endprint:; /* is this a checking move? */ do_move( m+i ); if( checktest(Color) ) sprintf( ss+strlen(ss), "+" ); undo_move( m+i ); if( s == NULL ) printf(ss); else strcpy( s, ss ); } void pvSAN( tmove *v, char *s ) { int n; tmove m[256]; int i; generate_legal_moves( m, &n, checktest(Color) ); for( i=0; i!=n; i++ ) if( smove(v) == smove(m+i) ) break; if( i != n ) { printmSAN( m, i, n, s ); do_move( m+i ); v++; if( v->from ) { sprintf( s+strlen(s), " " ); pvSAN( v, s+strlen(s) ); } undo_move( m+i ); } } #endif /* GNU Chess `X' understands only moves in `g1f3' notation. We have to send * this to older versions of xboard when playing phalanx with gnu. */ void gnuprintm(tmove m) { switch( m.special ) { case LONG_CASTLING: printf("o-o-o"); return; case SHORT_CASTLING: printf("o-o"); return; } printf( "%c%c%c%c%c", file[m.from%10], row[m.from/10], file[m.to%10], row[m.to/10], m.in2a == m.in1 ? ' ' : tolower(piece[m.in2a>>4]) ); } /** *** Return pointer to move in m[] if it matches the SAN representation. *** If there is no such move, return NULL. **/ tmove * sandex( char *inp, tmove *m, int n ) { char bufik[32]; char *s = bufik; char * ss; char * sto; int move,to; int i; unsigned p=0; int frow=0, ffile=0; int in2a=0; int color = color(m->in1); int sc=-1; int lc=-1; strncpy(bufik,inp,30); for( i=0; i!=n; i++ ) if(m[i].special==SHORT_CASTLING) sc=i; else if(m[i].special==LONG_CASTLING) lc=i; /*** step 0: castlings ***/ if( lc != -1 ) if( strncmp(s,"o-o-o",5)==0 || strncmp(s,"O-O-O",5)==0 || strncmp(s,"0-0-0",5)==0 || ( strncmp(s,"e1c1",4)==0 && color==WHITE ) || ( strncmp(s,"e8c8",4)==0 && color==BLACK ) ) return m+lc; if( sc != -1 && s[3]!='-' ) if( strncmp(s,"o-o",3)==0 || strncmp(s,"O-O",3)==0 || strncmp(s,"0-0",3)==0 || ( strncmp(s,"e1g1",4)==0 && color==WHITE ) || ( strncmp(s,"e8g8",4)==0 && color==BLACK ) ) return m+sc; /*** step 1: noncastling move must start with PNBRQKabcdefgh ***/ /*** if it starts with pnrqk, do the letter upercase ***/ { static char ok[] = "PNBRQKabcdefghpnrqk"; static char up[] = "pnrqk"; for( i=0; ok[i]!=*s; i++ ) if( ok[i] == '\0' ) return(NULL); for( i=0; up[i]!='\0'; i++ ) if( up[i] == *s ) { *s = toupper(*s); break; } } /*** step 2: find the destination square ***/ /* Find the last digit <1-8> in the input string. It must * be the row of the destination square and must be preceded * by letter of the dest. square **********************/ sto=NULL; for( ss=s+1; *ss!='\0'; ss++ ) if( *ss>='1' && *ss<='8' ) sto = ss-1; if( sto == NULL ) { if( ( s[2]=='\0' || s[2]=='\n' ) && s[1]>='a' && s[1]<='h' && s[0]>='a' && s[0]<='h' ) { /* exception: pawn capture can be typed as 'ef' */ int mn=-1; /* printf("trying exception %c %c %c\n", s[0], s[1], s[2] ); */ for( i=0; i!=n; i++ ) if( piece(m[i].in1) == PAWN ) if( m[i].from%10 == s[0]+1-'a' ) if( m[i].to%10 == s[1]+1-'a' ) if( mn==-1 ) mn=i; else mn=-2; if( mn>=0 ) return m+mn; } return NULL; /* no digit 1-8 found */ } for( i=1; i!=9; i++ ) if(file[i]==*sto) break; if(i==9) return NULL; to = i; for( i=2; i!=10; i++ ) if(row[i]==sto[1]) break; if(i==10) return NULL; to += i*10; /*** step 3: find the origin square ***/ /* 3a - try to find full description of origin square (g1f3) */ ss=sto-1; if(ss>=s) for( ss=sto-1; ss!=s; ss-- ) if( *ss>='1' && *ss<='8' && *(ss-1)>='a' && *(ss-1)<='h' ) { for( i=2; i!=10; i++ ) if(row[i]==*ss) break; frow = i; ss--; for( i=1; i!=9; i++ ) if(file[i]==*ss) break; ffile = i; for(i=0;i!=n;i++) if(m[i].from==frow*10+ffile) { p=m[i].in1; break; } goto step4; } /* 3b - origin square must be computed from piece */ { for(p=6;p!=1;p--) if( piece[p] == *s ) { s++; break; } p = (p<<4) + color; if( *s!='x' && s='a' && *s<='h' ) ffile = *s-'a'+1; else if( *s>='1' && *s<='8' ) frow = *s-'1'+2; } } step4:; /*** step 4: is it a pawn promotion? determine piece ***/ in2a = p; sto += 2; if( *sto == '=' ) sto++; *sto = toupper(*sto); for(i=2;i!=7;i++) if( piece[i]==*sto ) in2a=(i<<4)+color; /*** step 5: scan move list ***/ move = -1; for(i=0;i!=n;i++) if( m[i].to==to && m[i].in1==p && m[i].in2a==in2a ) if( ffile==0 || ffile==m[i].from%10 ) if( frow==0 || frow==m[i].from/10 ) { if(move==-1) move=i; else return NULL; } if(move==-1) return NULL; return m+move; } /** *** Is the string represented move ("Pe2-e4") same as the tmove move? *** This correctly parses almost anything but not SAN - we dont have *** full move list. **/ int checkmove( char *s, tmove *m ) { int i; if( m->special == LONG_CASTLING ) if( strncmp(s,"o-o-o",5)==0 || strncmp(s,"O-O-O",5)==0 || strncmp(s,"0-0-0",5)==0 || ( Color == WHITE && strncmp(s,"e1c1",4) == 0 ) || ( Color == BLACK && strncmp(s,"e8c8",4) == 0 ) ) return 1; else return 0; if( m->special == SHORT_CASTLING ) if( ( strncmp(s,"o-o",3)==0 && strncmp(s,"o-o-o",5)!=0 ) || ( strncmp(s,"O-O",3)==0 && strncmp(s,"O-O-O",5)!=0 ) || ( strncmp(s,"0-0",3)==0 && strncmp(s,"0-0-0",5)!=0 ) || ( Color == WHITE && strncmp(s,"e1g1",4) == 0 ) || ( Color == BLACK && strncmp(s,"e8g8",4) == 0 ) ) return 1; else return 0; for( i=0; s[i]!='\0' && ! islower(s[i]); i++ ); if( s[i]=='\0' || s[i]!=file[m->from%10] ) return 0; i++; if( s[i]=='\0' || s[i]!=row[m->from/10] ) return 0; for( ; s[i]!='\0' && ( s[i]=='x' || ! islower(s[i]) ); i++ ); if( s[i]=='\0' || s[i]!=file[m->to%10] ) return 0; i++; if( s[i]=='\0' || s[i]!=row[m->to/10] ) return 0; i++; if( m->in2a != m->in1 ) { if( s[i] == '=' || s[i] == ':' ) i++; if( toupper(s[i]) != piece[m->in2a>>4] ) return 0; } return 1; } void printPV( int mpl, int lid, char *s ) /* mpl ... moves per line */ { char ss[1024] = ""; int j; #ifdef SHOW_FORCED_MOVES if( mpl>2 ) mpl -= 2; #endif #ifdef SANOUT int k=0; int l=lid; char s1[1024] = ""; pvSAN( PV[0], s1 ); for( j=0; s1[j]!='\0'; j++,l++ ) if( l <= 72 || s1[j] != ' ' ) { ss[k] = s1[j]; k++; } else { ss[k] = '\n'; k++; for( l=0; l!=lid; l++ ) { ss[k] = ' '; k++; } } ss[k] = '\0'; #else for(j=0;PV[0][j].from;j++) { if( j%mpl == 0 && j != 0 && Flag.xboard!=2 ) { int i; sprintf( ss+strlen(ss), "\n" ); for( i=0; i!=lid; i++ ) sprintf( ss+strlen(ss), " " ); } printm( PV[0][j], ss+strlen(ss) ); } if( j < 3 ) sprintf( ss+strlen(ss), " " ); #endif sprintf( ss+strlen(ss), "\n" ); if( s == NULL ) printf(ss); else strcpy(s,ss); } void infoline( int typ, char *s ) { /** typ: *** 0 ... search finished, summary information *** 1 ... normal 'xboard' line, known eval, time, full PV *** 2 ... '!' - turn, new best move *** 3 ... summary informations at the end of ply level, no PV *** 4 ... '??' - first move fails low *** 5 ... '!!' - current move fails high, over window **/ char ss[1024]; extern long T1; long t = ptime(); if( typ!=0 && !Flag.analyze && ( Abort || t-T1 < Flag.noise ) ) return; if( Flag.log && s==NULL ) { int x = Flag.xboard; Flag.xboard = 0; infoline(typ,ss); Flag.xboard = x; fprintf(Flag.log, ss); } if( Flag.xboard == 2 ) switch( typ ) { case 0: /* ICS whispering */ if( Flag.ponder<2 && Flag.xboard>1 && typ==0 ) { printf( "tellics whisper depth=%i; eval=%c%i.%02i; nodes=%lli; nps=%i\n", A_d, PV[0][0].value>=0 ? '+' : '-', abs(PV[0][0].value/100), abs(PV[0][0].value)%100, Nodes, (int)( ((float)Nodes) / (((float)max(t-T1,1))/100) ) ); /* printPV(8,5,ss); printf("tellics whisper %s",ss); */ } return; case 3: typ=1; break; } if( typ >= 1 && typ <= 5 ) { sprintf( ss, "%3i", A_d ); if( typ==1 || typ==2 || typ==4 || typ == 5 ) sprintf( ss+strlen(ss), "%7i", PV[0][0].value ); else if( typ == 3 ) sprintf( ss+strlen(ss), " -> " ); if( typ == 3 ) { long tt = (long) (ptime()-T1); long t = tt / 100; sprintf( ss+strlen(ss), "%3i:%02i.%02li", (int)t/60, (int)t%60, tt*100/100-t*100 ); } else { sprintf( ss+strlen(ss), " %5li", (long)(t-T1) ); } sprintf( ss+strlen(ss), " %8lli ", Nodes ); } else { sprintf( ss, "Depth=%i, Value=%i, Time=%i.%02i, Last turn=%i.%02i, Nodes=%i", (int) A_d, (int) PV[0][0].value, (int) (t-T1)/100, (int) (t-T1)%100, (int) (LastTurn-T1)/100, (int) (LastTurn-T1)%100, (int) Nodes ); if( t-T1 != 0 ) sprintf( ss+strlen(ss), ", N/s=%i\n", (int) ( (float) Nodes / ( (float)(t-T1)/(float)100 ) ) ); else sprintf( ss+strlen(ss), "\n" ); } switch( typ ) { case 0: sprintf( ss+strlen(ss), "PV = " ); printPV(8,5,ss+strlen(ss)); if( PV[0][0].value > CHECKMATE-100 ) sprintf( ss+strlen(ss), " Mate in %i\n", (CHECKMATE-PV[0][0].value+1) / 2 ); break; case 1: printPV(6,27,ss+strlen(ss)); break; case 2: printm( PV[0][0], ss+strlen(ss) ); sprintf( ss+strlen(ss), "! \n" ); break; case 3: sprintf( ss+strlen(ss), "%2i turn", Turns ); if(Turns==1) sprintf( ss+strlen(ss), " \n"); else sprintf( ss+strlen(ss), "s \n"); break; case 4: printm( PV[0][0], ss+strlen(ss) ); sprintf( ss+strlen(ss), "?? \n" ); break; case 5: printm( PV[0][0], ss+strlen(ss) ); sprintf( ss+strlen(ss), "!! \n" ); } if( s != NULL ) strcpy( s, ss ); else { printf(ss); } } void verboseline( tmove* m, int i, int n ) { char s[256]; int j; extern long T1; long t = (long) (ptime()-T1) / 100; sprintf( s, "(%2i)", A_d ); sprintf( s+strlen(s), " "); sprintf( s+strlen(s), "%3li:%02li ", t/60, t%60 ); sprintf( s+strlen(s), "%9lli ", Nodes ); sprintf( s+strlen(s), "(%2i/%2i) ", i+1, n ); printm( m[i], s+strlen(s) ); sprintf( s+strlen(s), " " ); for( j=0; j!=79; j++ ) sprintf( s+strlen(s), "" ); printf(s); } void printboard(char *s) { int i; char ss[2048]; sprintf(ss, " +---+---+---+---+---+---+---+---+\n "); for(i=A8;i>=A1;i++) { switch(color(B[i])) { case WHITE: sprintf(ss+strlen(ss),"| %c ",piece[B[i]>>4]); break; case BLACK: sprintf(ss+strlen(ss),"| *%c",piece[B[i]>>4]); break; default: sprintf(ss+strlen(ss),"| "); } if( i%10 == 8 ) { i-=18; sprintf(ss+strlen(ss), "|\n +---+---+---+---+---+---+---+---+"); if(i!=10) sprintf(ss+strlen(ss),"\n "); } } if( Color == WHITE ) sprintf(ss+strlen(ss)," White to move\n"); else sprintf(ss+strlen(ss)," Black to move\n"); if( s==NULL ) printf(ss); else strcpy(s,ss); /* printf("%08X\n",G[Counter].hashboard); */ } /** *** The setfen() function is one of the two ways to set a position. *** The second one is edit(). **/ int setfen( char *f ) { int s; if( Flag.log != NULL ) { fprintf(Flag.log,"\n\nsetting position\n"); fprintf(Flag.log,f); fprintf(Flag.log,"\n\n"); } for( s=0; s!=120; s++ ) if( s>H8 || s=A1; f++ ) { if( *f == '\0' ) { puts("error: unexpected end of fen line"); return 1; } if( isdigit(*f) ) /* skip squares */ { s += *f - ('1'-1); continue; } switch( *f ) { case 'K': B[s] = WK; L[1].next=s; break; case 'k': B[s] = BK; L[2].next=s; break; case 'Q': B[s] = WQ; break; case 'q': B[s] = BQ; break; case 'R': B[s] = WR; break; case 'r': B[s] = BR; break; case 'B': B[s] = WB; break; case 'b': B[s] = BB; break; case 'N': B[s] = WN; break; case 'n': B[s] = BN; break; case 'P': B[s] = WP; break; case 'p': B[s] = BP; break; case '/': case ' ': case ';': s -= s%10 + 10; break; default: puts("error in fen line"); return 1; } s++; } switch( tolower(*f) ) { case 'w': Color = WHITE; break; case 'b': Color = BLACK; break; default: puts("error: side to move must be either 'w' or 'b'"); return 1; } initbs(); return 0; } /** *** If an entered string contains seven (or more) slashes *** it is considered as fen test position. **/ int sevenslashes(register char *s) { register int n=7; while( *s!='\0' && *s!=' ' ) { if(*s=='/') { n--; if(!n) return 1; } s++; } return 0; } /** *** Is the current position terminal? *** returns: 0 ... not terminal *** 1 ... draw, 50 moves or 3rd repetition; ok to continue play *** 2 ... draw, stalemate *** 3 ... checkmate **/ int terminal(void) { tmove m[256]; int n, c; if( G[Counter].rule50>=100 || repetition(2) || material_draw() ) { if(Flag.machine_color==(WHITE|BLACK)) Flag.machine_color=0; return 1; } generate_legal_moves( m, &n, c=checktest(Color) ); if( n!=0 ) return 0; if(c) return 3; else return 2; } void printpositionfen(void) { int s, empty_counter=0, Castling=0; #define EMPTY_COUNTER if (empty_counter) { printf("%d", empty_counter); empty_counter=0; }; for( s=A8; s>=A1; s++ ) { switch( B[s] ) { case WK: EMPTY_COUNTER; printf("K"); break; case BK: EMPTY_COUNTER; printf("k"); break; case WQ: EMPTY_COUNTER; printf("Q"); break; case BQ: EMPTY_COUNTER; printf("q"); break; case WR: EMPTY_COUNTER; printf("R"); break; case BR: EMPTY_COUNTER; printf("r"); break; case WB: EMPTY_COUNTER; printf("B"); break; case BB: EMPTY_COUNTER; printf("b"); break; case WN: EMPTY_COUNTER; printf("N"); break; case BN: EMPTY_COUNTER; printf("n"); break; case WP: EMPTY_COUNTER; printf("P"); break; case BP: EMPTY_COUNTER; printf("p"); break; default: empty_counter++; break; } if( s%10 == 8 ) { EMPTY_COUNTER; s-=18; if (s!=H1-18) printf("/"); else printf(" "); } } if( Color == WHITE ) printf("w "); else printf("b "); /****** White Short ******/ if( ( G[Counter].castling & WSHORT ) == 0 ) { printf("K"); Castling++;} /****** White Long ******/ if( ( G[Counter].castling & WLONG ) == 0 ) { printf("Q"); Castling++;} /****** Black Short ******/ if( ( G[Counter].castling & BSHORT ) == 0 ) { printf("k"); Castling++;} /****** Black Long ******/ if( ( G[Counter].castling & BLONG ) == 0 ) { printf("q"); Castling++;} if (!Castling) printf("- "); else printf(" "); if( Counter != 0 ) { int c = Counter-1; if( piece(G[c].m.in1) == PAWN && abs(G[c].m.from-G[c].m.to) == 20 ) /* The last move was a pawn double step */ { int destination; int special = G[c].m.to; destination = Color==WHITE ? special+10 : special-10; printf("%c%c ", file[destination%10], row[destination/10]); } else printf("- "); } else printf("- "); printf("%d %d\n", G[Counter].rule50, Counter/2+1); } void about(void) { printf(" Phalanx "); puts(VERSION); puts(" Copyright (C) Dusan Dobes, 1997-2000"); printf(" Level ................. "); switch( Flag.level ) { case averagetime: printf( "average time %i seconds\n", Flag.centiseconds/100 ); break; case timecontrol: printf( "%i moves in %i minutes\n", Flag.moves, Flag.centiseconds/6000 ); break; case fixeddepth: printf( "%i search depth\n", Flag.depth/100 ); break; case fixedtime: printf( "fixed time %i seconds\n", Flag.centiseconds/100 ); } printf(" Time .................. "); if( Flag.cpu ) puts("cpu"); else puts("elapsed"); printf(" Book .................. "); if( Flag.book ) puts("on"); else puts("off"); printf(" Learning .............. "); if( Flag.learn ) puts("on"); else puts("off"); printf(" Permanent brain ....... "); switch( Flag.ponder ) { case 0: puts("off"); break; case 1: puts("on"); break; case 2: puts("on (pondering)"); break; default: ; } printf(" Transposition table ... "); if( SizeHT == 0 ) puts("not used"); else { printf("hashing %i positions in %lu bytes\n", SizeHT, (unsigned long)(sizeof(thashentry)*SizeHT) ); } if( Flag.easy ) { printf(" Easy level ............ %i\n",Flag.easy); } printf(" Resigning ............. "); if( Flag.resign ) printf("%i.%02i\n",Flag.resign/100,Flag.resign%100); else printf("off\n"); printf("\n"); } /* SIG_INT handler */ void interrupt(int x) { int c; signal(SIGINT,SIG_IGN); if( Flag.polling ) { /* ignore lines that begin with '.' */ c=getc(stdin); ungetc(c,stdin); if( c=='.' ) { fgets(Inp,255,stdin); goto go_on; } } if( Flag.ponder < 2 ) { puts("interrupted"); Abort = 1; goto go_on; } while( command() ) {} go_on:; if( !Abort && !Flag.polling ) signal(SIGINT,interrupt); } int command(void) { static int no_prompt = 0; if( Flag.xboard < 2 ) if( no_prompt ) no_prompt = 0; else if( Flag.ponder >= 2 ) printf("\n[ pondering ]\n"); else printf( "[ %s, %i ]\n", Color==WHITE ? "white" : "black", Counter/2+1 ); if( Inp[0] == '\0' ) if( fgets(Inp,255,stdin) == NULL ) strcpy(Inp,"quit\n"); if( strncmp(Inp,"exit\n",5) == 0 && Flag.analyze ) { Flag.machine_color = Flag.analyze = 0; Inp[0]='\0'; return 1; } if( strncmp(Inp,"quit\n",5) == 0 || strncmp(Inp,"exit\n",5) == 0 ) { if( Flag.ponder < 2 ) return 0; else { Abort = 1; return 0; } } /* COMMAND: comment */ if( Inp[0]=='#' ) { printf("%s",Inp); no_prompt = 1; Inp[0]='\0'; return 1; } /* COMMAND: no op */ if( Inp[0]=='\n' ) { Inp[0]='\0'; if( Flag.ponder >= 2 ) return 0; /* continue search */ else return 1; } /* COMMAND: analyze */ if( strncmp( Inp, "analyze\n", 8 ) == 0 ) { if( Flag.ponder >= 2 ) { Abort = 1; return 0; } puts("analyze mode, type 'exit' to terminate"); Flag.analyze = 1; Flag.machine_color = 3; Inp[0]='\0'; return 1; } /* COMMAND: force */ if( strncmp( Inp, "force\n", 6 ) == 0 ) { if( Flag.ponder >= 2 ) { Abort = 1; return 0; } puts("you play both"); if( Flag.analyze ) Flag.machine_color = Color; else Flag.machine_color = 0; Inp[0]='\0'; return 1; } /* COMMANDS: white, black */ if( strncmp( Inp, "white\n", 6 ) == 0 || strncmp( Inp, "black\n", 6 ) == 0 ) { if( Flag.ponder >= 2 ) { Abort = 1; return 0; } puts("you do not play both"); if( Flag.machine_color == 0 ) Flag.machine_color = enemy(Color); Inp[0]='\0'; return 1; } /* COMMAND: both */ if( strncmp( Inp, "both\n", 5 ) == 0 ) { if( Flag.ponder >= 2 ) { Abort = 1; return 0; } puts("machine plays both"); Flag.machine_color = 3; Inp[0]='\0'; return 1; } /* COMMAND: new */ if( strncmp( Inp, "new\n", 4 ) == 0 ) { if( Flag.ponder >= 2 ) { Abort = 1; return 0; } setfen("rnbqkbnr/pppppppp/////PPPPPPPP/RNBQKBNR/w"); DrawScore = -20; if( Flag.analyze ) Flag.machine_color = WHITE; else { Flag.machine_color = BLACK; puts("initial position set, machine plays black"); } Inp[0]='\0'; return 1; } /* COMMAND: go */ if( strncmp( Inp, "go\n", 3 ) == 0 ) { if( Flag.ponder >= 2 ) { Abort = 1; return 0; } Flag.machine_color = Color; Inp[0]='\0'; return 1; } /* COMMAND: bd */ if( strncmp( Inp, "bd\n", 3 ) == 0 || strncmp( Inp, "d\n", 2 ) == 0 ) { printboard(NULL); Inp[0]='\0'; return 1; } /* COMMAND: bk */ if( strncmp( Inp, "bk\n", 3 ) == 0 ) { tmove m[256]; int n; extern void bk(tmove *, int ); if( Flag.ponder >= 2 ) { Abort = 1; return 0; } generate_legal_moves( m, &n, checktest(Color) ); bk(m,n); /* printf("%08X\n",G[Counter].hashboard); */ Inp[0]='\0'; return 1; } /* COMMAND: post */ if( strncmp( Inp, "post\n", 5 ) == 0 ) { Flag.post = 1; puts("post on"); Inp[0]='\0'; return 1; } /* COMMAND: nopost */ if( strncmp( Inp, "nopost\n", 7 ) == 0 ) { Flag.post = 0; puts("post off"); Inp[0]='\0'; return 1; } /* COMMAND: level */ if( strncmp( Inp, "level ", 6 ) == 0 ) { l_level( Inp+6 ); Inp[0]='\0'; return 1; } /* COMMAND: time */ if( strncmp( Inp, "time ", 5 ) == 0 ) { sscanf( Inp+5, "%li", &Time ); Inp[0]='\0'; return 1; } /* COMMAND: otim */ if( strncmp( Inp, "otim ", 5 ) == 0 ) { sscanf( Inp+5, "%li", &Otim ); Inp[0]='\0'; return 1; } /* COMMAND: rating */ if( strncmp( Inp, "rating ", 7 ) == 0 ) { int phal, oppo, diff; if( sscanf( Inp+7, "%i %i", &phal, &oppo ) == 2 ) { diff = oppo-phal; if( diff > 300 ) DrawScore = 20; else if( diff < -300 ) DrawScore = -20; else DrawScore = diff/15; printf("setting draw score to %i\n",DrawScore); Inp[0]='\0'; return 1; } } /* COMMAND: hard */ if( strncmp( Inp, "hard\n", 5 ) == 0 ) { if( Flag.ponder==0 && Flag.easy==0 ) Flag.ponder = 1; if(Flag.ponder) puts("pondering on"); Inp[0]='\0'; return 1; } /* COMMAND: easy */ if( strncmp( Inp, "easy\n", 5 ) == 0 ) { if( Flag.ponder != 0 ) { if( Flag.ponder >= 2 ) { Abort = 1; return 0; } Flag.ponder = 0; } puts("pondering off"); Inp[0]='\0'; return 1; } /* COMMAND: beep, draw, ... ignored */ if( strncmp( Inp, "beep\n", 5 ) == 0 || strncmp( Inp, "bogus\n", 6 ) == 0 || strncmp( Inp, "draw\n", 5 ) == 0 || strncmp( Inp, "name ", 5 ) == 0 || strncmp( Inp, "random\n", 7 ) == 0 || strncmp( Inp, "noise ", 6 ) == 0 || strncmp( Inp, ".\n", 2 ) == 0 ) { /* ignore */ Inp[0]='\0'; return 1; } /* COMMAND: depth */ if( strncmp( Inp, "depth", 5 ) == 0 ) { int newdepth; if( Inp[5] == '\n' ) { printf("depth= "); scanf( "%i", &newdepth ); } else { sscanf( &Inp[6],"%i",&newdepth); } Flag.depth = 100*newdepth; if( Flag.depth < 200 ) Flag.depth = 200; else if( Flag.depth > MAXPLY*100 ) Flag.depth = MAXPLY*100; Flag.level = fixeddepth; printf("search depth %i\n", Flag.depth/100 ); Inp[0]='\0'; return 1; } /* COMMAND: book */ if( strncmp( Inp, "book\n", 5 ) == 0 ) { Flag.book = ! Flag.book; if( Flag.book ) puts("book on"); else puts("book off"); Inp[0]='\0'; return 1; } /* COMMAND: about */ if( strncmp( Inp, "about\n", 6 ) == 0 ) { about(); Inp[0]='\0'; return 1; } /* COMMAND: fen */ if( strncmp( Inp, "fen\n", 3 ) == 0 ) { printpositionfen(); Inp[0]='\0'; return 1; } /* COMMAND: help */ if( strncmp( Inp, "help\n", 5 ) == 0 ) { puts("COMMAND SUMMARY: about (shows settings), bd (displays position - same"); puts("as 'd'), bk (shows book info), book (enables/disables book), both"); puts("(machine plays both), depth (set search depth), fen, force (user"); puts("plays both, go (start computing), help, history (show game moves),"); puts("level , level , new (new game), post (show thinking), remove (take back last"); puts("move, two plies), nopost (do not show thinking), quit (same as 'exit'"); puts("or end of file character), score (show static evaluation), time "); puts("(remaining time is N/100 s), undo (undo last ply - same as 'u'),"); puts(" (set test position, start search, show result),"); puts("# (comment)"); Inp[0]='\0'; return 1; } /* COMMAND: score */ if( strncmp( Inp, "score\n", 6 ) == 0 ) { Scoring = 1; Depth = 100; printf("\n (stm) material = %i\n", G[Counter].mtrl-G[Counter].xmtrl); printf(" TOTAL EVALUATION = %i\n", score_position() ); printf("Wknow.hung=%i; Wknow.khung=%i\n", Wknow.hung, Wknow.khung); printf("Bknow.hung=%i; Bknow.khung=%i\n", Bknow.hung, Bknow.khung); puts(""); Scoring = 0; Inp[0]='\0'; return 1; } /* COMMAND: xboard */ if( strncmp( Inp, "xboard\n", 7 ) == 0 ) { Flag.xboard = 2; puts("xboard mode on"); Inp[0]='\0'; return 1; } /* COMMAND: history */ if( strncmp( Inp, "history\n", 8 ) == 0 ) { int i; int sc = (Counter+Color+1) % 2; if( sc ) printf("\n 1. ... "); for( i=0; i= 2 ) { Abort = 1; return 0; } if( Counter != 0 ) { undo_move( & G[Counter-1].m ); if(Flag.xboard<2) puts("halfmove back"); if( Flag.machine_color != 0 ) Flag.machine_color = enemy(Color); if( Flag.analyze ) Flag.machine_color = Color; } else puts("cannot undo"); Inp[0]='\0'; return 1; } /* COMMAND: remove (xboard) */ if( strncmp( Inp, "remove\n", 7 ) == 0 ) { if( Flag.ponder >= 2 ) { Abort = 1; return 0; } if( Counter > 1 ) { undo_move( & G[Counter-1].m ); undo_move( & G[Counter-1].m ); if(Flag.xboard<2) puts("move back"); if( Flag.machine_color != 0 ) Flag.machine_color = enemy(Color); } else puts("cannot remove"); Inp[0]='\0'; return 1; } /* COMMAND: edit (xboard) */ if( strncmp( Inp, "edit\n", 5 ) == 0 ) { if( Flag.ponder >= 2 ) { Abort = 1; return 0; } edit(); if( Flag.analyze ) Flag.machine_color = 3; else Flag.machine_color = 0; if( Inp[0]=='e' ) Inp[0]='\0'; return 1; } /* COMMAND: test a position */ if( sevenslashes(Inp) ) /* test */ { if( Flag.ponder >= 2 ) { Abort = 1; return 0; } if( setfen(Inp) == 0 ) { static int entered=0; static int found=0; int f=0; tmove m; int i; printf("\n%s",Inp); m = root_search(); Flag.machine_color = 0; if( ! Flag.post ) { Depth += 100; infoline(0,NULL); } entered++; for( i=0; Inp[i]!='\0'; i++ ) if( checkmove( Inp+i, &m ) ) { f=1; found++; break; } if( f ) printf("[ Solution correct "); else { FILE * nf; /* not found */ static char filename[16] = "notfound.fin"; if( entered-found == 1 ) nf = fopen(filename,"w"); else nf = fopen(filename,"a"); if( nf != NULL ) { fputs( Inp, nf ); fclose(nf); } printf("[ Solution incorrect "); } printf(" %i.%02i%%, %i/%i ]\n", found*100/entered, found*10000/entered%100, found, entered); no_prompt = 1; } Inp[0]='\0'; return 1; } /* suppose this is an user move */ if( Flag.ponder >= 2 ) { tmove *pm = sandex(Inp,Pm,Pn); if(pm!=NULL) if( pm->from == Pondermove.from && pm->to == Pondermove.to && pm->in1 == Pondermove.in1 && pm->in2 == Pondermove.in2 && pm->in2a == Pondermove.in2a && pm->special == Pondermove.special ) { Flag.ponder = 1; if( ! l_iterate() ) Abort = 2; else if( !Flag.polling ) signal(SIGINT,interrupt); Inp[0] = '\0'; return 0; } Abort = 1; return 0; } if( terminal() < 2 ) { tmove m[256]; int n; int i; generate_legal_moves( m, &n, checktest(Color) ); { tmove *sd = sandex(Inp,m,n); if(sd!=NULL) i=sd-m; else i=n; } if( i != n ) { printf("\nyour move is "); printm( m[i], NULL ); puts(""); do_move( m+i ); switch( terminal() ) { case 1: puts("1/2-1/2 {Drawn game}"); break; case 2: puts("1/2-1/2 {Stalemate}"); break; case 3: if( Color == WHITE ) puts("0-1 {Black mates}"); else puts("1-0 {White mates}"); } Inp[0]='\0'; return 1; } } /*** UNKNOWN COMMAND / ILLEGAL MOVE ***/ { char *c=strchr(Inp,'\n'); if(c!=NULL) *c='\0'; else *Inp='\0'; } printf("Illegal move: %s\n",Inp); Inp[0] = '\0'; return 1; } void shell(void) { while( command() ) { while( ( Flag.machine_color & Color ) && terminal() < 2 ) { tmove m; m = root_search(); if( Flag.analyze ) { undo_move(&m); Flag.machine_color = enemy(Color); continue; } if( Flag.ponder >= 2 ) { Flag.ponder = 1; undo_move(&m); undo_move(&Pondermove); continue; } if( Flag.machine_color == 3 && Abort == 1 ) Flag.machine_color = 0; { int ter; if( Flag.resign != 0 ) { static int resign=0; if( m.value < -Flag.resign && Counter > 20 ) resign++; else resign=0; if( resign > 3 && Otim > 2000 /* oppo must have 20 s */ && Otim + Flag.increment*900 > 9000 /* && m.value > -CHECKMATE+100 */ ) { if( Flag.xboard ) puts("tellics resign"); if( Color == WHITE ) puts("1-0 {Black resigns}"); else puts("0-1 {White resigns}"); } } printf("my move is "); printm( m, NULL ); if( Flag.xboard ) { printf("\n%i. ... ",(Counter+1)/2); gnuprintm(m); } puts(""); switch( ( ter = terminal() ) ) { case 1: puts("1/2-1/2 {Drawn game}"); continue; case 2: puts("1/2-1/2 {Stalemate}"); continue; case 3: if( Color == WHITE ) puts("0-1 {Black mates}"); else puts("1-0 {White mates}"); continue; } if( Flag.ponder == 1 && Flag.machine_color != 3 && ter < 2 && ( Abort != 0 || Abort != 4 ) ) { int i; Pondermove = PV[0][1]; generate_legal_moves(Pm,&Pn,checktest(Color)); for( i=0; i!=Pn; i++ ) if( Pondermove.from == Pm[i].from && Pondermove.to == Pm[i].to && Pondermove.in1 == Pm[i].in1 && Pondermove.in2a == Pm[i].in2a ) break; if( i==Pn ) { if( Flag.post ) { puts("No move to ponder from PV."); puts("Looking for a move to ponder."); } if( Bookout < 4 || Counter < 10 ) i = bookmove( Pm, Pn ); else i = -1; if( i != -1 ) { Pondermove = Pm[i]; if( Flag.post ) puts("Found in book."); } else { if( Flag.post ) puts("Trying search."); Depth = -100; NoAbort = 1; Ply = 1; search(Pm,Pn,-CHECKMATE,CHECKMATE); NoAbort = 0; Pondermove = PV[1][1]; } for( i=0; i!=Pn; i++ ) if( Pondermove.from == Pm[i].from && Pondermove.to == Pm[i].to && Pondermove.in1 == Pm[i].in1 && Pondermove.in2a == Pm[i].in2a ) break; if( i==Pn ) { if(Flag.post) puts("No move found. A bug?"); i=0; } else { if(Flag.post) puts("Done."); } } if( i != Pn ) { /* OK, the move was also found in just * generated list of moves, not only in * the PV (principal variation). Let's * ponder then!!! ********************/ do_move(&Pondermove); if( terminal() > 1 ) undo_move(&Pondermove); else { if( Flag.post ) { printf("Hint: "); printm(Pondermove,NULL); puts(""); } Flag.ponder = 2; } } } continue; } } } }