/***************************************************************************/ /* micro-Max, */ /* A chess program smaller than 2KB (of non-blank source), by H.G. Muller */ /***************************************************************************/ /* version 1.6 (1433 non-blank characters) features: */ /* - recursive negamax search */ /* - quiescence search with recaptures */ /* - recapture extensions */ /* - (internal) iterative deepening */ /* - best-move-first 'sorting' */ /* - full FIDE rules and move-legality checking */ /* accepts under-promotions: type 1,2,3 (=R,B,N) after input move */ /* (input buffer c[] & *P made global, K and N encoding swapped for this) */ /* fused to generic Winboard driver */ #include #include #include #include #include #include int StartKey; #define EMPTY 0 #define WHITE 8 #define BLACK 16 #define STATE 64 /* make unique integer from engine move representation */ #define PACK_MOVE 256*K + L; /* convert intger argument back to engine move representation */ #define UNPACK_MOVE(A) K = (A)>>8 & 255; L = (A) & 255; /* Global variables visible to engine. Normally they */ /* would be replaced by the names under which these */ /* are known to your engine, so that they can be */ /* manipulated directly by the interface. */ int Side; int Move; int PromPiece; int Result; int TimeLeft; int MovesLeft; int MaxDepth; int Post; int Fifty; int UnderProm; int Ticks, tlim; int GameHistory[1024]; char HistoryBoards[1024][STATE]; int GamePtr, HistPtr; #define W while #define W while int M=136,S=128,I=8e3,C=799,Q,O,K,N; char L,*P, w[]={0,1,1,-1,3,3,5,9}, o[]={-16,-15,-17,0,1,16,0,1,16,15,17,0,14,18,31,33,0, 7,-1,6,11,8,3,6, 6,4,5,7,3,5,4,6}, b[129], n[]=".?+knbrq?*?KNBRQ", c[9]; D(k,q,l,e,E,z,n) int k,q,l,e,E,z,n; { int j,r,m,v,d,h,i,F,G,s; char t,p,u,x,y,X,Y,H,B; q--; d=X=Y=0; W(d++1?-I:e; N++; do{u=b[x]; if(u&k) {r=p=u&7; j=o[p+16]; W(r=p>2&r<0?-r:-o[++j]) {A: y=x;F=G=S; do{ H=y=h?Y^h:y+r; if(y&M)break; m=E-S&&b[E]&&y-E<2&E-y<2?I:m; /* castling-on-Pawn-check bug fixed */ if(p<3&y==E)H^=16; t=b[H];if(t&k|p<3&!(y-x&7)-!t)break; i=99*w[t&7]; m=i<0?I:m; /* castling-on-Pawn-check bug fixed */ if(m>=l)goto C; if(s=d-(y!=z)) {v=p<6?b[x+8]-b[y+8]:0; b[G]=b[H]=b[x]=0;b[y]=u|32; if(!(G&M))b[F]=k+6,v+=30; if(p<3) {v-=9*((x-2&M||b[x-2]-u)+ (x+2&M||b[x+2]-u)-1); if(y+r+1&S)b[y]|=7,i+=C; } v=-D(24-k,-l,m>q?-m:-q,-e-v-i,F,y,s); if(K-I) {if(v+I&&x==K&y==L&z==8) {Q=-e-i;O=F; if(b[y]-u&7)b[y]-=PromPiece; /* under-promotions */ Fifty = t|p<3?0:Fifty+1; return l; }v=m; } b[G]=k+6;b[F]=b[y]=0;b[x]=u;b[H]=t; if(v>m) m=v,X=x,Y=y|S&F; if(h){h=0;goto A;} } if(x+r-y|u&32| p>2&(p-3|j-7|| b[G=x+3^r>>1&7]-k-6 ||b[G^1]|b[G^2]) )t+=p<5; else F=y; }W(!t); }}}W((x=x+9&~M)-B); C:if(m>I-M|m>4),'a'+(Y&7),'8'-(Y>>4&7)),fflush(stdout); } if(z==S+1)K=X,L=Y&~M; return m+=m=100) { printf("1/2-1/2 {Draw by fifty move rule}\n"); return 4; } return 0; } InitEngine() { int j; K=8;W(K--) {L=8;W(L--)b[16*L+K+8]=(K-4)*(K-4)+(L-3.5)*(L-3.5); /* center-pts table */ } /*(in unused half b[])*/ } InitGame() { int i,j; for(i=0;i<128;i++)b[i&~M]=0; K=8;W(K--) {b[K]=(b[K+112]=o[K+24]+8)+8;b[K+16]=18;b[K+96]=9; /* initial board setup*/ } /*(in unused half b[])*/ Side = WHITE; Q=0; O=S; Fifty = 0; UnderProm = -1; } void CopyBoard(int s) { int j, k, cnt=0; /* copy game representation of engine to HistoryBoard */ /* don't forget castling rights and e.p. state! */ for(j=0; j<64; j++) HistoryBoards[s][j] = b[j+(j&0x38)]; /* board squares */ if(!(O&M)) HistoryBoards[s][O+(O&7)>>1] |= 64; /* mark ep square */ } int main(int argc, char **argv) { int Computer, MaxTime, MaxMoves, TimeInc, sec, i; char line[256], command[256]; int m, nr; signal(SIGINT, SIG_IGN); printf("tellics say micro-Max 1.6w\n"); printf("tellics say by H.G. Muller\n"); InitEngine(); InitGame(); Computer = EMPTY; MaxTime = 10000; /* 10 sec */ MaxDepth = 97; /* maximum depth of your search */ for (;;) { fflush(stdout); if (Side == Computer) { /* think up & do move, measure time used */ /* it is the responsibility of the engine */ /* to control its search time based on */ /* MovesLeft, TimeLeft, MaxMoves, TimeInc */ /* Next 'MovesLeft' moves have to be done */ /* within TimeLeft+(MovesLeft-1)*TimeInc */ /* If MovesLeft<0 all remaining moves of */ /* the game have to be done in this time. */ /* If MaxMoves=1 any leftover time is lost*/ Ticks = GetTickCount(); m = MovesLeft<=0 ? 40 : MovesLeft; tlim = 0.4*(TimeLeft+(m-1)*TimeInc)/(m+7); PromPiece = 0; N=0;K=I; if (D(Side,-I,I,Q,O,8,2)==I) { Side ^= 24; if(UnderProm>=0 && UnderProm != L) { printf("tellics I hate under-promotions!\n"); printf("resign\n"); Computer = EMPTY; continue; } else UnderProm = -1; printf("move "); printf("%c%c%c%c",'a'+(K&7),'8'-(K>>4), 'a'+(L&7),'8'-(L>>4)); printf("\n"); m = (GetTickCount() - Ticks)/10; /* time-control accounting */ TimeLeft -= m; TimeLeft += TimeInc; if(--MovesLeft == 0) { MovesLeft = MaxMoves; if(MaxMoves == 1) TimeLeft = MaxTime; else TimeLeft += MaxTime; } GameHistory[GamePtr++] = PACK_MOVE; CopyBoard(HistPtr=HistPtr+1&1023); if(PrintResult(Side)) Computer = EMPTY; } else { if(!PrintResult(Side)) printf("resign\n"); Computer = EMPTY; } continue; } if (!fgets(line, 256, stdin)) return; if (line[0] == '\n') continue; sscanf(line, "%s", command); if (!strcmp(command, "xboard")) continue; if (!strcmp(command, "new")) { /* start new game */ InitGame(); GamePtr = 0; HistPtr = 0; Computer = BLACK; TimeLeft = MaxTime; MovesLeft = MaxMoves; for(nr=0; nr<1024; nr++) for(m=0; m>1); while(MaxMoves>0 && MovesLeft<=0) MovesLeft += MaxMoves; continue; } if (!strcmp(command, "hint")) { Ticks = GetTickCount(); tlim = 1000; D(Side,-I,I,Q,O,S+1,6); if (K==0 && L==0) continue; printf("Hint: "); printf("%c%c%c%c",'a'+(K&7),'8'-(K>>4), 'a'+(L&7),'8'-(L>>4)); printf("\n"); continue; } if (!strcmp(command, "undo") && (nr=1) || !strcmp(command, "remove") && (nr=2) ) { /* 'take back' moves by replaying game */ /* from history until desired ply */ if (GamePtr < nr) continue; GamePtr -= nr; HistPtr -= nr; /* erase history boards */ while(nr-- > 0) for(m=0; m= 'a' && line[1] <= 'h' && line[2] >= '1' && line[2] <= '8') { m = line[1]-16*line[2]+C; switch(line[0]) { case 'P': if(color==WHITE) b[m]=(m&0x70)==0x60?9:41; else b[m]=(m&0x70)==0x10?18:50; break; case 'N': b[m]=3+color; break; case 'B': b[m]=5+color; break; case 'R': b[m]=6+color+32; if((m==0x00 || m==0x07) && color==BLACK || (m==0x70 || m==0x77) && color==WHITE) b[m] -= 32; break; case 'Q': b[m]=7+color; break; case 'K': b[m]=4+color+32; if(m==0x04 && color==BLACK || m==0x74 && color==WHITE) b[m] -= 32; break; } continue; } } continue; } /* command not recognized, assume input move */ m = line[0]<'a' | line[0]>'h' | line[1]<'1' | line[1]>'8' | line[2]<'a' | line[2]>'h' | line[3]<'1' | line[3]>'8'; switch(line[4]) { case '\n': case 'q': PromPiece=0; break; case 'r': PromPiece=1; break; case 'b': PromPiece=2; break; case 'n': PromPiece=3; break; } {char *c=line; K=c[0]-16*c[1]+C;L=c[2]-16*c[3]+C; } if (m) /* doesn't have move syntax */ printf("Error (unknown command): %s\n", command); else if(D(Side,-I,I,Q,O,8,2)!=I) /* did have move syntax, but illegal move */ printf("Illegal move:%s\n", line); else { /* legal move, perform it */ GameHistory[GamePtr++] = PACK_MOVE; Side ^= 24; CopyBoard(HistPtr=HistPtr+1&1023); if(PrintResult(Side)) Computer = EMPTY; } } }