fairymax-4.8q/0000755000175000017500000000000011477644744013306 5ustar vincentvincentfairymax-4.8q/changelog0000644000175000017500000001366211477644744015170 0ustar vincentvincent/***************************************************************************/ /* micro-Max version 4.8 (~1950 characters) features: */ /* - recursive negamax search */ /* - all-capture quiescence search with MVV/LVA priority */ /* - (internal) iterative deepening */ /* - best-move-first 'sorting' */ /* - a hash table storing score and best move */ /* - futility pruning */ /* - king safety through magnetic frozen king */ /* - null-move pruning */ /* - Late-move reductions */ /* - full FIDE rules (expt minor promotion) and move-legality checking */ /* - keep hash + rep-draw detect */ /* - end-game Pawn-push bonus, new piece values, gradual promotion */ /***************************************************************************/ /* The Fairy-Max version reads the piece description from a file fmax.ini */ /* The format supports many fairy pieces, including hoppers. */ /* f) now supports 15 piece types, by requisitioning WHITE bit */ /* g) supports larger board width. */ /* h) castling bug ('in-check by non-captures') corrected */ /* i) rep-draw bug ('side-to-move') corrected */ /* k) allow user underpromotions, recognize & ignore 'variant' command */ /* l) edit bug corrected (i & j file clear) */ /* m) piece values no longer quantized, game-stage counting bug corrected */ /* n) edit-menu K-side castling bug corrected. */ /* o) retrieve the requested variant from the .ini file */ /* p) clear hash table on variant switch */ /* q) reduced piece-material count for better Pawn push */ /* r) hash-table bug corrected (X still ORed with flags) */ /* s) Bug that prevented initialization center points corrected */ /* t) castling bug after edit fixed */ /* u) converted to protocol 2; ping implemented */ /* v) white e.p. rights hash bug fixed; */ /* w) piece indicators programable, multi-path support */ /* x) e.p. changed to support Berolina Pawns */ /* y) capture value of 6-7th-rank Pawn reduced in Shatranj */ /* z) bug in promotion input corrected */ /* A) stalemate-detection bug in printResult fixed */ /* B) Invalidate hash on game-level promotion (might be under-promotion!) */ /* C) King move evaluation based on negative piece value in stead of nr */ /* D) WB memory command added, undo fixed */ /* E) 15th piece read in */ /* F) accepts ini fileargument */ /* G) bug in calculation ASCII promotion character fixed */ /* H) unified normal and shatranj source */ /* J) rewrite under-promotion code, fixes persistent bug there */ /* K) o[] and oo[] made int to make fairymax work on big-endian machines */ /* L) added Resign option feature (using new WB protocol) */ /* M) char -> signed char for better portability */ /* N) add PV printing and multi-PV support */ /* O) non-Rook castling, 6th-rank promotion, independent B/W piece naming */ /***************************************************************************/ 4/6/2009 Unified source of ShaMax and Fairy-Max into single fmax.c file, and created this ChangeLog from the until then self-documenting source. 6/2/2009 Promotion code rewitten to not refer to default piece characters. 9/3/2009 Fixed big-endian bug in reading inifile (char with int format), and added some option features to make Fairy-Max useful as test engine for GUIs that want to implement the WB protocol extensions. 9/16/2009 Made signedness of char in AI explicit 27/12/2009 Added PV updating through the triangular-array method. Also added a multi-PV option to print lines within a certain sccore margin. 15/1/2010 Improved Makefile, updated docs Implement independent naming of white and black pieces. (So mirror- image pieces can use same letter.) Change castling code to allow castling with any corner piece type. Implement 6th-rank promotion based on 'Queen' value. Makruk added as new variant to the fmax.ini file. 16/1/2010 Fixed bug in Shatranj result claims. Flip eval sign when side-to-move changes through WB color command. 17/1/2010 Removed Shatranj stalemate claim again, as it was never triggered. 1/11/2010 Implement counting of pieces, and extinction win condition. Add engine option to allow subdivision of variant fairy. Add FIDE vs Nutty Knights as variant fairy/FIDE-Nutters Allow white and black to promote to a different piece type. 2/11/2010 Implement duple-check rule. Add Spartan Chess as variant to fmax.ini. Update docs. 1/12/2010 Version 4.8Q, implementing a reverse setup command for sending pieceToCharTable and initial position to the GUI, sub-specification of variant fairy through an engine-defined option, allowing Seirawan- type gating moves in search. Seirawan Chess is added as new variant, pluss several new combinations of Chess with different armies fairymax-4.8q/copyright0000644000175000017500000000147611477644744015251 0ustar vincentvincentThis package was debianized by H.G.Muller on Fri Jun 5 20:42:56 CEST 2009. Upstream Author(s): H.G. Muller Copyright: Copyright (C) 2009 H.G. Muller License: Fairy-Max 4.8 is free software, and you have permission do with it whatever you want, whether it is commercial or not. Note, however, that Fairy-Max can easily be configured through its fmax.ini file to play Chess variants that are legally pro- tected by patents, and to do so would also require permission of the holders of such patents. No guarantees are given that Fairy-Max does anything in particular, or that it would not wreck the hardware it runs on, and running it is entirely for your own risk. The Debian packaging is (C) H.G.Muller. fairymax-4.8q/fairymax.c0000644000175000017500000011455111477644744015301 0ustar vincentvincent/***************************************************************************/ /* fairy-Max, */ /* Version of the sub-2KB (source) micro-Max Chess program, fused to a */ /* generic WinBoard interface, loading its move-generator tables from file */ /***************************************************************************/ /*****************************************************************/ /* LICENCE NOTIFICATION */ /* Fairy-Max 4.8 is free software, and you have my permission do */ /* with it whatever you want, whether it is commercial or not. */ /* Note, however, that Fairy-Max can easily be configured through*/ /* its fmax.ini file to play Chess variants that are legally pro-*/ /* tected by patents, and that to do so would also require per- */ /* mission of the holders of such patents. No guarantees are */ /* given that Fairy-Max does anything in particular, or that it */ /* would not wreck the hardware it runs on, and running it is */ /* entirely for your own risk. H.G,Muller, author of Fairy-Max */ /*****************************************************************/ #define MULTIPATH #define VERSION "4.8Q" #include #include #include #include #include #ifndef INI_FILE #define INI_FILE "fmax.ini" #endif #ifdef WIN32 # include #else # include int GetTickCount() // with thanks to Tord { struct timeval t; gettimeofday(&t, NULL); return t.tv_sec*1000 + t.tv_usec/1000; } #endif int StartKey; #define EMPTY -1 #define WHITE 0 #define BLACK 16 #define STATE 128 /* The following macros indicate the differences between Fairy-Max and its */ /* dedicated Shatranj derivative ShaMax so that these can now be compiled */ /* from the same unified source file. */ /* Compile with gcc option -DSHATRANJ to build ShaMax. */ #ifdef SHATRANJ # define FAC 175 # define EG 13 # define NAME "ShaMax" # define SHAMAX(x) x # define FMAX(x) #else # define FAC 128 # define EG 10 # define NAME "Fairy-Max" # define SHAMAX(x) # define FMAX(x) x #endif /* make unique integer from engine move representation */ #define PACK_MOVE 256*K + L + (PromPiece << 16); /* convert intger argument back to engine move representation */ #define UNPACK_MOVE(A) K = (A)>>8 & 255; L = (A) & 255; PromPiece = (A)>>16 & 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 GameNr; int Resign; int Threshold = 800; int Score; int makruk; int prom, pm, gating; char piecename[32], piecetype[32], blacktype[32]; char selectedFairy[80]; char *inifile = INI_FILE; int Ticks, tlim, Setup, SetupQ; int GameHistory[1024]; char HistoryBoards[1024][STATE], setupPosition[162]; int GamePtr, HistPtr; #define W while #define K(A,B) *(int*)(T+A+S*(B&31)) #define J(A) K(y+A,b[y])-K(x+A,u)-K(H+A,t) int U=(1<<23)-1; struct _ {int K,V;char X,Y,D,F;} *A; /* hash table, 16M+8 entries*/ int M=136,S=128,I=8e3,Q,O,K,N,j,R,J,Z,LL,GT, /* M=0x88 */ BW,BH,sh, w[16]={0,2,2,-1,7,8,12,23,7,5}, /* relative piece values */ o[256], oo[32], /* initial piece setup */ of[256], od[16]; /* 1st dir. in o[] per piece*/ signed char L,pl[32], b[513], /* board: 16x8+dummy, + PST */ T[4104], /* hash translation table */ centr[32], n[]=".*XKNBRQEWFMACHG?x+knbrqewfmachg"; /* piece symbols on printout*/ int pv[10000],*sp=pv; // triangular array int margin; pboard() {int i; i=-1;W(++i<128)printf(" %c",(i&15)==BW&&(i+=15-BW)?10:n[b[i]&31]); } D(k,q,l,e,E,z,n) /* recursive minimax search, k=moving side, n=depth*/ int k,q,l,e,E,z,n; /* (q,l)=window, e=current eval. score, E=e.p. sqr.*/ { /* e=score, z=prev.dest; J,Z=hashkeys; return score*/ int j,r,m,v,d,h,i,F,G,P,V,f=J,g=Z,C,s,flag,FF,*ps=sp,kk=S; signed char t,p,u,x,y,X,Y,H,B,gt; struct _*a=A+(J+(k+S)*E&U-1); /* lookup pos. in hash table*/ *sp++=0; q-=qD;m=a->V;X=a->F;Y=a->Y; /* resume at stored depth */ if(a->K-Z|z&S | /* miss: other pos. or empty*/ !(m<=q|X&8&&m>=l|X&S)) /* or window incompatible */ d=Y=0; /* start iter. from scratch */ X=a->X; /* start at best-move hint */ W(d++2&&l+I?D(16-k,-l,1-l,-e,2*S,2*S,d-3):I; /* search null move */ m=-P beta unconsidered:static eval */ SHAMAX( if(pl[k]<=1&pl[16-k]>1)m=I-1; ) /* bare king loses */ N++; /* node count (for timing) */ do{u=b[x]; /* scan board looking for */ if(u&&(u&16)==k) /* own piece (inefficient!)*/ {r=p=u&15; /* p = piece type (set r>0) */ j=od[p]; /* first step vector f.piece*/ W(r=o[++j]) /* loop over directions o[] */ {A: /* resume normal after best */ flag=h?3:of[j]; /* move modes (for fairies) */ y=x;F=FF=G=S; /* (x,y)=move, (F,G)=castl.R*/ do{ /* y traverses ray, or: */ H=y=h?Y^h:y+r; /* sneak in prev. best move */ if(flag&1<<8)H=y=(y&15)>13?y+BW:(y&15)>=BW?y-BW:y; /* cylinder board */ if(y&S|(y&15)>=BW)break; /* board edge hit */ #ifdef MULTIPATH if(flag&1<<9) /* if multipath move */ {t=flag>>12; /* get dir. stepped twice */ if(b[x+t]){if(b[y-2*t]|b[y-t])break;}else if(b[x+2*t]&&b[y-t])break; /* test if empty path exists*/ } #endif m=E<16|(E^112)<16&&flag&1&y-E<2&E-y<2?I:m; /* bad castling */ if(p<3&y==E)H=z&127; /* shift capt.sqr. H if e.p.*/ t=b[H]; if(flag&1+!t) /* mode (capt/nonc) allowed?*/ {if(t&&(t&16)==k)break; /* capture own */ i=w[t&15]+((t&192)>>sh); /* value of capt. piece t */ if(i<0&&(pl[t&31]<2|| /* K capture, (of last K), */ t>>3&kk!=H&kk!=S||(kk=H,i=-i,0)))m=I,d=98;/* or duple check: cutoff*/ if(m>=l&d>1)goto C; /* abort on fail high */ v=d-1?e:i-p; /*** MVV/LVA scoring if d=1**/ if(d-!t>1) /*** all captures if d=2 ***/ {v=gt=0;G: /* retry move with gating */ v+=centr[p]?b[x+257]-b[y+257]:0; /* center positional pts. */ if(!(G&S))b[FF]=b[G],v+=50; /* castling: put R & score */ b[G]=b[H]=0;b[x]=gt;b[y]=u|32; /* do move, set non-virgin */ pl[t&31]-=!!t; /* updat victim piece count */ v-=w[p]>0|R>2); /* end-game Pawn-push bonus */ b[y]+=V=y+r+1&S?647-p|pm:2*(u&y+16&32);/*upgrade P or convert to Q*/ if(V&makruk)b[y]=u|7,V=480; /* Makruk promotion on 6th */ V>>=sh; /* for Shatranj promo to F */ i+=V; /* promotion / passer bonus */ } if(z&S && GamePtr<6) v+=(rand()>>10&31)-16; J+=J(0);Z+=J(4)+G-S; SHAMAX( pl[k]-=!!t; ) /* count pieces per side */ v+=e+i;V=m>q?m:q; /*** new eval & alpha ****/ if(z&S)V=m-margin>q?m-margin:q; /* multiPV */ C=d-1-(d>5&p>2&!t&!h); /* nw depth, reduce non-cpt.*/ C=R2|v>V?-D(16-k,-l,-V,-v,/*** futility, recursive eval. of reply */ F,y&255,C):v; W(s>q&++CV&vD=99;a->V=0; /* lock game in hash as draw*/ R-=i/FAC; /*** total captd material ***/ Fifty = t|p<3?0:Fifty+1; sp=ps; return l;} /* & not in check, signal */ v=m; /* (prevent fail-lows on */ } /* K-capt. replies) */ SHAMAX( pl[k]+=!!t; ) pl[t&31]+=!!t; b[G]=b[FF];b[FF]=b[y]=0;b[x]=u;b[H]=t; /* undo move,G can be dummy */ } /* if non-castling */ if(z&S&&K==I&d>2&v>V&v>8;Y=*p++; printf(" %c%c%c%c",'a'+(X&15),'8'-(X>>4),'a'+(Y&15),'8'-(Y>>4&7));} printf("\n");fflush(stdout); }GT=gt; /* In root, remember gated */ } if(v>m) /* new best, update max,best*/ m=v,X=x,Y=y|S&F; /* mark non-double with S */ if(gating&&!(u&32)&&p>2&&d-!t>1){ /* virgin non-Pawn: gate */ pl[(gt|=k+40)-27]++; /* prev. gated back in hand */ if(m>=l)goto C; /* loop skips cutoff :-( */ W(++gt>12; /* calc. alternated vector */ if(flag&15^4|u&32|| /* no double or moved before*/ p>2&& /* no P & no lateral K move,*/ ((b[G=r<0?x&~15:BW-1|x&112]^32)<33 /* no virgin R in corner G, */ ||b[G^1]|b[G^2]|b[FF=y+v-r]) /* no 2 empty sq. next to R */ )t+=flag&4; /* fake capt. for nonsliding*/ else if(flag&64)t=flag&128?0:t,flag&=63;else F=y; /* enable e.p. */ if(s&&flag&8)t=0,flag^=flag>>4&15; /* hoppers go to next phase */ if(!(flag&S)) /* zig-zag piece? */ r=v,flag^=flag>>4&15; /* alternate vector & mode */ }W(!t); /* if not capt. continue ray*/ }} if((++x&15)>=BW)x=x+16&112; /* next sqr. of board, wrap */ }W(x-B); C:FMAX( m=m+I|P==I?m:(X=Y=0); ) /* if stalemate, draw-score */ if(a->D<99) /* protect game history */ a->K=Z,a->V=m,a->D=d,a->X=X, /* always store in hash tab */ a->F=8*(m>q)|S*(mY=Y; /* move, type (bound/exact),*/ } /* encoded in X S,8 bits */ if(z&4*S)K=X,L=Y&~S; sp=ps; return m+=m 1) /* third repeat */ { printf("1/2-1/2 {Draw by repetition}\n"); return 1; } differs: ; } K=I; cnt = D(s,-I,I,Q,O,LL|4*S,3); #ifdef SHATRANJ if(pl[s]==1 && pl[16-s]==1) { printf("1/2-1/2 {Insufficient mating material}\n"); return 4; } if(pl[s]<=1 && pl[16-s]>1) { if (s == BLACK) printf("0-1 {Bare King}\n"); else printf("1-0 {Bare King}\n"); return 5; } #else if(cnt>-I+1 && K==0 && L==0) { printf("1/2-1/2 {Stalemate}\n"); return 2; } #endif if(cnt==-I+1) { if (s == WHITE) printf("0-1 {Black mates}\n"); else printf("1-0 {White mates}\n"); return 3; } if(Fifty >=100) { printf("1/2-1/2 {Draw by fifty move rule}\n"); return 4; } return 0; } InitEngine() { int i, j; N=32*S+7;W(N-->S+3)T[N]=rand()>>9; srand(GetTickCount()); } InitGame() { int i,j,k=0; Side = WHITE; Q=0; O=S; Fifty = 0; R = 0; for(i=0;i<16*BH;i++)b[i]=0; for(i=0;i<32;i++)pl[i]=0; K=BW;W(K--) {b[K]=oo[K+16]+16;b[K+112]=oo[K];b[K+16]=18;b[K+96]=1; /* initial board setup*/ pl[oo[K+16]+16]++;pl[oo[K]]++;pl[18]++;pl[1]++; if(w[oo[K+16]+16] == -1)pl[oo[K+16]+16]=1; if(w[oo[K]] == -1)pl[oo[K]]=1; L=8;W(L--)b[16*L+K+257]=(K-BW/2)*(K-BW/2)+(L-3.5)*(L-3.5); /* center-pts table */ } /*(in unused half b[])*/ for(i=0; i12 || BH!=8) { printf("telluser unsupported board size %dx%d\n",BW,BH); exit(0); } for(i=0; i='a'; blacktype[c&31]=i; piecename[i]=c&31; if(piecetype[c&31]==0) piecetype[c&31]=i; // only first } j++; o[j]=0; /* printf("# c='%c' i=%d od[i]=%d j=%d (%3d,%8x)\n",c?c:' ',i,od[i],j,o[j-1],of[j-1]); /**/ c=0; if(i>15 || j>255) break; } fclose(f); sh = w[7] < 250 ? 3 : 0; makruk = w[7]==181 ? 64 : 0; // w[7] is used as kludge to enable makruk promotions if(name == selectedFairy) { printf(ptc == 1 ? "setup " : "setup (%s) ", pieceToChar); // setup board in GUI for(i=0; i1 && sscanf(argv[1], "%d", &m)==1) { U = (1<1) inifile = argv[1]; signal(SIGINT, SIG_IGN); printf("tellics say " NAME " " VERSION "\n"); printf("tellics say by H.G. Muller\n"); printf("tellics say Gothic Chess is protected by U.S. patent #6,481,716 by Ed Trice.\n"); printf("tellics say Falcon Chess is protected by U.S. patent #5,690,334 by George W. Duke\n"); InitEngine(); LoadGame(NULL); InitGame(); Computer = EMPTY; MaxTime = 10000; /* 10 sec */ MaxDepth = 30; /* 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.6-0.06*(BW-8))*(TimeLeft+(m-1)*TimeInc)/(m+7); if(tlim>TimeLeft/15) tlim = TimeLeft/15; PromPiece = 0; /* Always promote to Queen ourselves */ N=0;K=I; if (D(Side,-I,I,Q,O,LL|S,3)==I) { Side ^= BLACK^WHITE; if(UnderProm>=0 && UnderProm != L) { printf("tellics I hate under-promotions!\n"); printf("resign { underpromotion } \n"); Computer = EMPTY; continue; } else UnderProm = -1; printf("move "); printf("%c%c%c%c",'a'+(K&15),'0'+BH-(K>>4), 'a'+(L&15),'0'+BH-(L>>4)); if(prom)printf("%c",piecename[prom&15]+'a'-1); printf("\n"); m = GetTickCount() - Ticks; /* 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(Resign && Score <= -Threshold) { printf("resign\n"); Computer=EMPTY; } else if(PrintResult(Side)) Computer = EMPTY; } else { if(!PrintResult(Side)) printf("resign { refuses own move }\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, "protover")) { printf("feature myname=\"" NAME " " VERSION "\"\n"); printf("feature memory=1\n"); printf("feature setboard=0 ping=1 done=0\n"); printf("feature variants=\""); PrintVariants(0); printf("\"\n"); PrintOptions(); continue; } if (!strcmp(command, "ping")) { int nr=0; sscanf(line, "ping %d", &nr); printf("pong %d\n", nr); continue; } if (!strcmp(command, "p")) { pboard(); continue; } if (!strcmp(command, "memory")) { int mem, mask; sscanf(line+6, "%d", &mem); mem = (mem*1024*1024)/12; // max nr of hash entries mask = 0x7FFFFFFF; while(mask > mem) mask >>= 1; if(mask != U) { free(A); U = mask; A = (struct _ *) calloc(U+1, sizeof(struct _)); } continue; } if (!strcmp(command, "new")) { /* start new game */ LoadGame("normal"); InitGame(); GamePtr = Setup = 0; GameNr++; HistPtr = 0; Computer = BLACK; TimeLeft = MaxTime; MovesLeft = MaxMoves; for(nr=0; nr<1024; nr++) for(m=0; mK = 0; if(sscanf(line+7, "MultiVariation Margin=%d", &margin) == 1) continue; if(sscanf(line+7, "Variant fairy selects=%s", selectedFairy+6) == 1) continue; continue; } if (!strcmp(command, "go")) { /* set computer to play current side to move */ Computer = Side; MovesLeft = -(GamePtr+(Side==WHITE)>>1); while(MaxMoves>0 && MovesLeft<=0) MovesLeft += MaxMoves; continue; } if (!strcmp(command, "hint")) { Ticks = GetTickCount(); tlim = 1000; D(Side,-I,I,Q,O,LL|4*S,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 < 0) continue; GamePtr -= nr; HistPtr -= nr; /* erase history boards */ while(nr-- > 0) for(m=0; m= 'A' && m <= 'Z' && piecetype[m&31] && line[1] >= 'a' && line[1] <= 'a'+BW-1 && line[2] >= '1' && line[2] <= '0'+BH) { m = line[1]-16*line[2]+799; switch(p = (color == WHITE ? piecetype : blacktype)[line[0]&31]) { case 1: case 2: if(color==WHITE) b[m]=(m&0x70)==0x60?1:33, Q+=w[1]; else b[m]=(m&0x70)==0x10?18:50, Q+=w[2]; break; default: b[m]=p+color+32; // assume non-virgin if(w[p]<0) { // Royal piece on original square: virgin if(color==BLACK && m<0x10 && p==oo[m+16] || color==WHITE && m>0x6F && p==oo[m-0x70]) b[m] -= 32; Q-=w[p]; // assume value was flipped to indicate royalty if(pl[p+color])R-=w[p]/FAC; // capturable King, add to material } else { Q+=w[p]; R+=w[p]/FAC; } if((m==0x00 || m==BW-1 ) && color==BLACK && p==oo[m+16] || (m==0x70 || m==0x6F+BW) && color==WHITE && p==oo[m-0x70]) b[m] &= ~32; // corner piece as in original setup: virgin case 0: // undefined piece, ignore break; } pl[BLACK+WHITE-color]++;pl[p+color]++; if(w[p+color] == -1)pl[p+color]=1; // fake we have one if value = -1, to thwart extinction condition continue; } } if(Side != color) Q = -Q; GamePtr = HistPtr = 0; Setup = 1; SetupQ = Q; // start anew for(i=0; i<128; i++) setupPosition[i] = b[i]; // remember position setupPosition[128] = Side; setupPosition[129] = R; for(i=0; i<32; i++) setupPosition[i+130] = pl[i]; Computer = EMPTY; // after edit: force mode! continue; } /* command not recognized, assume input move */ m = line[0]<'a' | line[0]>='a'+BW | line[1]<'1' | line[1]>='1'+BH | line[2]<'a' | line[2]>='a'+BW | line[3]<'1' | line[3]>='1'+BH; if(line[4] == '\n') line[4] = 0; GT = (Side == WHITE ? piecetype : blacktype)[line[4]&31]; if(GT) PromPiece = (Side == WHITE ? 7 : 7+pm) - GT, GT |= 32 + Side; {char *c=line; K=c[0]-16*c[1]+799;L=c[2]-16*c[3]+799; } if (m) /* doesn't have move syntax */ printf("Error (unknown command): %s\n", command); else { int i=-1; if(b[L] && (b[L]&16) == Side && w[b[L]&15] < 0) // capture own King: castling { i=K; K = L; L = i>L ? i-1 : i+2; } if(b[K]&32) GT = 0; // non-virgin mover => true promotion rather than gating if(D(Side,-I,I,Q,O,LL|S,3)!=I) { /* did have move syntax, but illegal move */ printf("Illegal move:%s\n", line); } else { /* legal move, perform it */ if(i >= 0) b[i]=b[K],b[K]=0; // reverse Seirawan gating GameHistory[GamePtr++] = PACK_MOVE; Side ^= BLACK^WHITE; CopyBoard(HistPtr=HistPtr+1&1023); if(PrintResult(Side)) Computer = EMPTY; } } } } fairymax-4.8q/fairymax.pod0000644000175000017500000001310311477644744015630 0ustar vincentvincent=head1 NAME fairymax - xboard-compatible chess and chess-variant engine 'Fairy-Max' =head1 SYNOPSIS B [hashSize] [iniFile] B [hashSize] [iniFile] B [hashSize] [iniFile] =head1 DESCRIPTION B is a program that plays chess and chess variants. It uses the xboard/winboard chess-engine protocol to communicate. Apart from 'regular' chess (also known as the Mad-Queen variant), it can play Capablanca chess, gothic chess, knightmate, cylinder chess, berolina chess, superchess, makruk (Thai chess), courier chess, Seirawan Chess, Spartan chess and chess with Different Armies. Fairy-Max can be easily configured by the user to play other variants as well, by modifying the ini file. This ini file describes the rules of movement of the participating pieces and the initial board setup. Fairy-Max can also play shatranj, but in this case is not aware of the shatranj rule that a bare king loses. So it might play sub-optimally in the late end-game. A version of Fairy-Max adapted to implement the baring rule is available under the name B. Similarly, a version of Fairy-Max adapted to play Xiang Qi (Chinese Chess) is included in the fairymax package as well, under the name B. B is a derivative of the world's (once) smallest chess program (source-code wise), micro-Max. The latter measures less that 2000 characters, (about 100 code lines), and has a computer rating of around 2050 on the CCRL rating list. Although this is about 1000 rating points behind the world champion, micro-Max still makes a quite tough opponent even for club players, although it is not unbeatable. The main difference between micro-Max and Fairy-Max is that the latter loads its move-generator tables, which specify how the various pieces move, from an external file, so it can be easily adapted to incorporate un-orthodox pieces. For ease of use of the artificial-intelligence, Fairy-Max is equipped with I/O routines that allow it to run with the xboard graphical user interface. See xboard(6) for instructions about how to use B through xboard. To start up quickly, you just need the command: B. However, XBoard might not support symbols for every unorthodox piece in board sizes different from B, B and B. It might thus be advisable to specify a board size as well, e.g. B to get correct display of the elephant and general pieces in shatranj. Note that to be able to play the chess variants, you will need xboard 4.3.14 or later. Some of the variants Fairy-Max plays are only partially supported by XBoard, and can only be played whith the legality-testing function of the latter switched off. (This applies to cylinder chess, berolina chess, great shatranj, Spartan chess and chess with different armies.) For some variants even the name is unknown to XBoard, and they are all grouped under the catchall name 'fairy'. Which variant is played by Fairy-Max when XBoard is set to 'fairy', can be determined by a combobox control in the XBoard 'Engine Settings' menu dialog. Fairymax supports multi-PV mode: by specifying a non-zero multi-PV margin in the Engine-Settings dialog of XBoard, Fairy-Max will not only print the principal variation for the best move, but also for every move that approaches the score of this best move to within the set margin. (If it does not find the best move on the first try, this might lead to printing of a few extra lines below the threshold.) The fmax.ini file from which Fairy-Max by default takes the piece and game definitions is a self-documenting text file, which contains instructions for how to define new pieces and chess variants. In addition it contains an extensive list of pre-defined pieces, incuding many not occurring in any of the pre-defined variants, which the user can draw on to define his own variants. Amongst the move types supported by Fairy-Max are normal leaper and slider moves, (e.g. knight and rook), divergent moves (i.e. capture and non-capture moves can be different) hoppers (which jump over other pieces, such as the Chinese cannon or the grasshopper), lame leapers (the move of which can be blocked on squares they cannot move to, such as the Chinese horse and elephant), and any combination thereof, in every possible direction. The board width is configurable upto a width of 14 squares, and cylindrical boards (where left and right edge connect) are supported as well. =head1 OPTIONS =over 8 =item B If the first argument to fairymax is numeric, it is taken as an indicator for the amount of memory Fairy-Max is allowed to use for its internal hash table. The default value for this argument, 22, would result in a memory usage of 48MB. Each next-higher number doubles the memory usage, each next-lower halves it. Running with less than 6MB (i.e. argument 19) is not recommended. When fairymax is running under xboard 4.3.15 the hash-table size can be set through the xboard menus, making this argument superfluous. =item B A second or non-numeric first argument is taken as a filename. Fairy-max will use the mentioned file in stead of its default fmax.ini file to define the movement of pieces and initial setup of the variants. This makes it easier to define your own variants. =back =head1 SEE ALSO xboard(6) http://www.chessvariants.org/index/msdisplay.php?itemid=MSfairy-max http://home.hccnet.nl/h.g.muller/max-src2.html http://www.open-aurec.com/wbforum/viewtopic.php?f=19&t=50387 =head1 AUTHOR B was written by H.G.Muller . This manual page was generated with pod2man(1). fairymax-4.8q/data/0000755000175000017500000000000011477644744014217 5ustar vincentvincentfairymax-4.8q/data/qmax.ini0000644000175000017500000000155611477644744015675 0ustar vincentvincentversion 4.8(w) 10x9 11 9 4 8 3 8 4 9 11 11 9 5 8 3 8 5 9 11 p:100 -1,7 p:100 1,7 k:-1 1,C07 16,C07 -1,C07 -16,C07 e:150 15,470 17,470 -15,470 -17,470 e:150 15,870 17,870 -15,870 -17,870 q:190 -1,7 16,7 -16,7 q:190 1,7 16,7 -16,7 A:200 15,C07 17,C07 -15,C07 -17,C07 h:450 16,1070 16,1F070 1,10070 1,FFFF0070 -16,1070 -16,1F070 -1,10070 -1,FFFF0070 C:460 1,BA 16,BA -1,BA -16,BA R:900 1,3 16,3 -1,3 -16,3 // Chinese Chess Game: xiangqi 10x9 11 9 4 8 3 8 4 9 11 11 9 5 8 3 8 5 9 11 p:100 -1,7 p:100 1,7 k:-1 1,C07 16,C07 -1,C07 -16,C07 e:150 15,470 17,470 -15,470 -17,470 e:150 15,870 17,870 -15,870 -17,870 q:190 -1,7 16,7 -16,7 q:190 1,7 16,7 -16,7 A:200 15,C07 17,C07 -15,C07 -17,C07 h:450 16,1070 16,1F070 1,10070 1,FFFF0070 -16,1070 -16,1F070 -1,10070 -1,FFFF0070 C:460 1,BA 16,BA -1,BA -16,BA R:900 1,3 16,3 -1,3 -16,3 // End of game file fairymax-4.8q/data/fmax.ini0000644000175000017500000005512511477644744015663 0ustar vincentvincentversion 4.8(w) 8x8 6 4 5 7 3 5 4 6 6 4 5 7 3 5 4 6 p:74 -16,24 -16,6 -15,5 -17,5 p:74 16,24 16,6 15,5 17,5 k:-1 1,34 -1,34 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7 n:259 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 b:296 15,3 17,3 -15,3 -17,3 R:444 1,3 16,3 -1,3 -16,3 Q:851 1,3 16,3 15,3 17,3 -1,3 -16,3 -15,3 -17,3 Some Common piece definitions: The board steps are encoded as follows: ^ toward 8th rank | -52 -51 -50 -49 -48 -47 -46 -45 -44 -36 -35 -34 -33 -32 -31 -30 -29 -28 -20 -19 -18 -17 -16 -15 -14 -13 -12 <-- -4 -3 -2 -1 start 1 2 3 4 --> towards h file to 12 13 14 15 16 17 18 19 20 a-file 28 29 30 31 32 33 34 35 36 44 45 46 47 48 49 50 51 52 | v towards first rank SIMPLE LEAPERS Ferz: f:150 15,7 17,7 -15,7 -17,7 Wazir: w:125 1,7 16,7 -1,7 -16,7 Knight: n:325 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 Dabbabah: d:100 2,7 32,7 -2,7 -32,7 Elephant: e:80 30,7 34,7 -30,7 -34,7 Camel: C:225 13,7 47,7 49,7 19,7 -13,7 -47,7 -49,7 -19,7 Zebra: Z:175 29,7 46,7 50,7 35,7 -29,7 -46,7 -50,7 -35,7 Unicorn: u:-1 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 COMPOUND LEAPERS King: k:-1 1,34 -1,34 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7 1,34 -1,34 King (Shatranj, no castling): k:-1 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7 1,34 -1,34 King (Capablanca castling): k:-1 2,3034 -2,1034 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7 Commoner: m:260 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7 Bison: 1000 13,7 47,7 49,7 19,7 -13,7 -47,7 -49,7 -19,7 29,7 46,7 50,7 35,7 -29,7 -46,7 -50,7 -35,7 Wildebeest: g:800 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 13,7 47,7 49,7 19,7 -13,7 -47,7 -49,7 -19,7 Carpenter: c:450 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 2,7 32,7 -2,7 -32,7 Kangaroo: o:450 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 30,7 34,7 -30,7 -34,7 High Priestess: h:625 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 30,7 34,7 -30,7 -34,7 15,7 17,7 -15,7 -17,7 Minister c:625 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 2,7 32,7 -2,7 -32,7 1,7 16,7 -1,7 -16,7 Crab: c:150 31,7 33,7 -14,7 -18,7 Barc: b:150 14,7 18,7 -31,7 -33,7 SEPARATE CAPTURES / NON-CAPTURES White Pawn: p:100 -16,6 -15,5 -17,5 -16,24 White Pawn (Shatranj, no double move): p:100 -16,6 -15,5 -17,5 White Berolina Pawn p:74 -15,24 -17,24 -16,5 -15,6 -17,6 Black Pawn: p:100 16,6 15,5 17,5 16,24 Pegasus (moves as Queen, captures as Rook): S:500 1,2 16,2 15,2 17,2 -1,2 -16,2 -15,2 -17,2 14,5 31,5 33,5 18,5 -14,5 -31,5 -33,5 -18,5 Keen (moves as King, captures as Queen): k:750 1,6 16,6 15,6 17,6 -1,6 -16,6 -15,6 -17,6 1,1 16,1 15,1 17,1 -1,1 -16,1 -15,1 -17,1 Quing (moves as Queen, captures as King): q:600 1,5 16,5 15,5 17,5 -1,5 -16,5 -15,5 -17,5 1,2 16,2 15,2 17,2 -1,2 -16,2 -15,2 -17,2 SLIDERS Bishop: b:350 15,3 17,3 -15,3 -17,3 Rook: R:500 1,3 16,3 -1,3 -16,3 NightRider: H:560 14,3 31,3 33,3 18,3 -14,3 -31,3 -33,3 -18,3 Queen: Q:950 1,3 16,3 15,3 17,3 -1,3 -16,3 -15,3 -17,3 LEAPER / SLIDER COMPOUNDS Archbishop: A:875 15,3 17,3 -15,3 -17,3 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 Caliph: C:875 15,3 17,3 -15,3 -17,3 13,7 47,7 49,7 19,7 -13,7 -47,7 -49,7 -19,7 Marshall: C:900 1,3 16,3 -1,3 -16,3 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 Canvasser: C:900 1,3 16,3 -1,3 -16,3 13,7 47,7 49,7 19,7 -13,7 -47,7 -49,7 -19,7 Amazon: A:1150 1,3 16,3 15,3 17,3 -1,3 -16,3 -15,3 -17,3 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 Crooked Bishop: B:900 15,1E003 17,1E003 -15,1E003 -17,1E003 15,FFFE0003 -17,FFFE0003 -15,FFFE0003 17,FFFE0003 HOPPERS GrassHopper: G:200 1,F8 16,F8 15,F8 17,F8 -1,F8 -16,F8 -15,F8 -17,F8 Cannon: C:400 1,BA 16,BA -1,BA -16,BA LAME LEAPERS Horse: N:5 16,1070 16,1F070 1,10070 1,FFFF0070 -16,1070 -16,1F070 -1,10070 -1,FFFF0070 Xiangqi Elephant: E:1 15,70 17,70 -15,70 -17,70 Syntax of a variant description: Each variant starts with the label "Game:" followed by the variant name. After that follow upto 18 lines with the description. Line 1: Board size (files x ranks). Ranks must currently still be 8. Line 2: initial setup of white pieces on back rank Line 3: initial setup of black pieces on back rank Line 4-18: Description of piece types that can occur in the variant There can be upto 15 piece types per variant, numbered 1 to 15. Numbers 1 and 2 are considered Pawns for white and black, respectively, and the 2nd and 7th rank of the opening setup will be filled with them. These pieces will automatically promote to piece number 7 when they reach last rank. So in normal Chess, piece 7 should be programmed as Queen. There is one exception to this: if the initial setup does have a white piece 7, but not a black one, and black has a piece number 9, then black will always promote to the latter. (This can be useful in variants with different armies for black and white). Castling can be done only with the original corner piece as specified by line 2 and 3. Any royal piece can in principle castle. (Subject to the normal restrictions on castling, i.e. not passing through check etc.) If you don't want that, remove the castling moves from the King description. If the castling initiator does not start in a central file, the results are currently undefined. Most variant definitions can be seen at the end of this file. Other lines in this file (i.e. those not recognized as belonging to a variant description) are ignored. They can be used for comments. In case you want to build your own pieces, this is how it works: The piece-description lines have the following syntax: 1) a piece-indicator character (lower case if piece should be centralized) 2) a colon 3) the internal value to be used for the piece (in centiPawn; Royal = -1) 4) for each direction it moves in, a ray descriptor consisting of: a) the initial step vector (on a 16x8 board, so 16 = straight ahead) b) a comma c) the move-mode descriptor, most easily given in hexadecimal, as the individual bits specify the various options The piece indicator character is used to set up positions, and for the promotion choice as 5th character of an input move. (Fairy-Max itself always promotes to "Queen", i.e. the 7th piece of the list.) If more pieces use the same letter, the first one is used for white, and the last one for black. If more than two have the same name, the others cannot be indicated at all, but they could still occur in the initial setup (where you specify them by number, not letter). Pieces with negative values are considered royal. If one side has more than one royal piece of the same type, he loses if the _last_ one is captured. This means any 'spare' royal pieces can be sacrificed, and the exchange value assumed for them will be the absolute value of what you defined. With a value -1, however, loss of the first piece of that type loses the game. For royal piece types larger than 7 there is the special rule that it is not allowed to leave more than one of them under attack ('duple check'). NOTE: piece value 181 for piece 7 is reserved for Makruk, and enables promotion on the 6th rank. Do not use it in other variants. The individual bits in the move-mode descriptor have the following meaning: In the last hexadecimal digit: 1 capture allowed (of enemy piece; own pieces always block a move) 2 con-capture allowed (i.e. we can move here if the square is empty) 4 leaper, i.e. move terminates after one step (as opposed to slider) 8 hop over non-empty square (normally occupied squares terminate a move) Bits set in the forelast digits TOGGLE the corresponding bits in the last digit. For hoppers when they hop over something, for the other pieces after every step (so for normal pieces, better not set those bits!). The digit before that can only be 0 or 1; a 1 indicates the board should be treated as a cylinder, pieces crossing the right edge re-entering the board at the left, and vice versa. The higher-order bits toggle corresponding bits in the step vector, to allow zig-zag paths. Better not set those either, if a straight path is desired. Useful bit combinations for the last digit are: 3 normal slider 7 normal leaper 6 leaper that only moves (e.g. Pawn straight ahead) 5 leaper that only captures (e.g. Pawn diagonal) 1 slider that only captures 2 slider that only moves 0 pass through (for testing emptiness by Xiangqi Horse and Elephant) 4 reserved for skip-step of Pawn double move and castling 8 skip to hopper platform (1st part of Grasshopper move) A non-capture before hop (1st part of Cannon move) C must hop immediately For example, if the initial step vector equals 1, and the descriptor is 11003, the piece is an alternator (as no hop bit is set), and alternates the mode from 3 to 3 (as the toggle digit is 0), i.e. all steps are moves that can both capture and non-capture, and only captures terminate the ray. The step vector is toggled by 11, though, and thus alternates between 1 and 10 (hex) = 16. So the piece zig-zags over the board, right, forward, right, forward, etc. Had the move attributes been 11032, captures would only be allowed on the odd steps (after moving right), while the even steps could only be non-captures (both the 1 and 2 bit are toggled). With 11030 the odd steps can only be skipped (if empty), and the even steps can both capture and non-capture, meaning the piece moves like a Bishop that can be blocked by a piece just next to the diagonal. If the first step is a slider, a second step is made (if the square was empty), but if the mode toggles to leaper, the move stops there (e.g. Horse). Hoppers MUST change into non-hoppers on hopping, i.e. the 8 bit of BOTH lower digits must be set. Otherwise results will be undefined. Note that the first two piece-describing lines MUST be for the white and black Pawn, respectively, or promotions will have undefined effects. Also note that uMax does do primitive evaluation of Pawn structure, which might become counter-productive if the Pawn move is changed. A low digit equal to 4 gets special treatment, as the normal interpretation as the last and only step of a move which can neither capture nor move is useles. It will in stead be used as if it was 0 (i.e. there is a follow-up step), but only if the piece has not moved before. If the 1 or 2 bit of the preceding toggle digit are set, they then determine what the move can do after this second step, in the normal way. (For pawn double-push and castling this would normally be a non-capture.) The 4 and 8 bits of this toggle digit are not used for toggling the leaper and hopper bits, though, but indicate if e.p. capture on the reply should be suppressed, and if the move should be allowed to continue even if the first step hits an occupied square. For the truly lazy, a few complete game descriptions can be found below: // FIDE Chess (a.k.a. Mad Queen variant) Game: normal 8x8 6 4 5 7 3 5 4 6 6 4 5 7 3 5 4 6 p:74 -16,24 -16,6 -15,5 -17,5 p:74 16,24 16,6 15,5 17,5 k:-1 1,34 -1,34 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7 n:259 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 b:296 15,3 17,3 -15,3 -17,3 R:444 1,3 16,3 -1,3 -16,3 Q:851 1,3 16,3 15,3 17,3 -1,3 -16,3 -15,3 -17,3 f:481 13,FFFFF207 29,F207 46,F207 47,10207 49,10207 50,11207 35,11207 19,1207 -13,1207 -29,FFFF1207 -46,FFFF1207 -47,FFFF0207 -49,FFFF0207 -50,FFFEF207 -35,FFFEF207 -19,FFFFF207 // Arabic precursor of modern Chess Game: shatranj 8x8 6 4 5 3 7 5 4 6 6 4 5 3 7 5 4 6 p:100 -16,6 -15,5 -17,5 p:100 16,6 15,5 17,5 k:-1 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7 n:450 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 b:110 30,7 34,7 -30,7 -34,7 R:630 1,3 16,3 -1,3 -16,3 q:180 15,7 17,7 -15,7 -17,7 e:110 30,7 34,7 -30,7 -34,7 f:180 15,7 17,7 -15,7 -17,7 // Thai Chess. Note: value m = 181 controls promotion at 6th! Game: makruk 8x8 6 4 5 7 3 5 4 6 6 4 8 3 7 8 4 6 p:100 -16,6 -15,5 -17,5 p:100 16,6 15,5 17,5 k:-1 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7 n:450 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 s:300 15,7 17,7 -15,7 -17,7 -16,7 R:630 1,3 16,3 -1,3 -16,3 m:181 15,7 17,7 -15,7 -17,7 s:300 15,7 17,7 -15,7 -17,7 16,7 f:181 15,7 17,7 -15,7 -17,7 q:181 15,7 17,7 -15,7 -17,7 b:300 15,7 17,7 -15,7 -17,7 -16,7 b:300 15,7 17,7 -15,7 -17,7 16,7 // Medieval intermediate between Shatranj and FIDE Chess Game: courier 12x8 6 4 8 5 10 3 7 9 5 8 4 6 6 4 8 5 10 3 7 9 5 8 4 6 p:65 -16,6 -15,5 -17,5 p:65 16,6 15,5 17,5 k:-1 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7 n:300 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 b:366 15,3 17,3 -15,3 -17,3 R:550 1,3 16,3 -1,3 -16,3 f:120 15,7 17,7 -15,7 -17,7 e:70 30,7 34,7 -30,7 -34,7 w:100 1,7 16,7 -1,7 -16,7 m:280 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7 // The King moves as a Knight, and vice versa Game: knightmate 8x8 6 4 5 7 3 5 4 6 6 4 5 7 3 5 4 6 p:74 -16,24 -16,6 -15,5 -17,5 p:74 16,24 16,6 15,5 17,5 k:-1 1,34 -1,34 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 m:222 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7 b:296 15,3 17,3 -15,3 -17,3 R:444 1,3 16,3 -1,3 -16,3 Q:851 1,3 16,3 15,3 17,3 -1,3 -16,3 -15,3 -17,3 // Modern variant with two new pieces (Archbishop and Chancellor) on 10x8 board Game: capablanca 10x8 6 4 8 5 7 3 5 9 4 6 6 4 8 5 7 3 5 9 4 6 p:100 -16,24 -16,6 -15,5 -17,5 p:100 16,24 16,6 15,5 17,5 k:-1 1,3034 -1,1034 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7 n:310 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 b:350 15,3 17,3 -15,3 -17,3 R:475 1,3 16,3 -1,3 -16,3 Q:950 1,3 16,3 15,3 17,3 -1,3 -16,3 -15,3 -17,3 A:825 15,3 17,3 -15,3 -17,3 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 C:875 1,3 16,3 -1,3 -16,3 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 e:1000 15,7 17,7 -15,7 -17,7 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 -1,7 1,7 -16,7 16,7 -1,34 1,34 -16,34 16,34 // Gothic Chess is protected through U.S. patent #6,481,716 by Ed Trice. // Spreading it without license might be a criminal offense! Game: gothic 10x8 6 4 5 7 9 3 8 5 4 6 6 4 5 7 9 3 8 5 4 6 p:100 -16,24 -16,6 -15,5 -17,5 p:100 16,24 16,6 15,5 17,5 k:-1 1,3034 -1,1034 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7 n:310 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 b:350 15,3 17,3 -15,3 -17,3 R:475 1,3 16,3 -1,3 -16,3 Q:950 1,3 16,3 15,3 17,3 -1,3 -16,3 -15,3 -17,3 A:825 15,3 17,3 -15,3 -17,3 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 C:875 1,3 16,3 -1,3 -16,3 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 // Cylinder Chess (WinBoard / XBoard legality testing should be off toplay this!) Game: cylinder 8x8 6 4 5 7 3 5 4 6 6 4 5 7 3 5 4 6 p:100 -16,24 -16,6 -15,105 -17,105 p:100 16,24 16,6 15,105 17,105 k:-1 1,34 -1,34 1,107 16,7 15,107 17,107 -1,107 -16,7 -15,107 -17,107 n:350 14,107 31,107 33,107 18,107 -14,107 -31,107 -33,107 -18,107 b:450 15,103 17,103 -15,103 -17,103 R:525 1,103 16,3 -1,103 -16,3 Q:1150 1,103 16,3 15,103 17,103 -1,103 -16,3 -15,103 -17,103 // Berolina Chess. In WinBoard 4.3.15 you can play this with legality testing switched off Game: berolina 8x8 6 4 5 7 3 5 4 6 6 4 5 7 3 5 4 6 p:74 -15,24 -17,24 -16,5 -15,6 -17,6 p:74 15,24 17,24 16,5 15,6 17,6 k:-1 1,34 -1,34 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7 n:259 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 b:296 15,3 17,3 -15,3 -17,3 R:444 1,3 16,3 -1,3 -16,3 Q:851 1,3 16,3 15,3 17,3 -1,3 -16,3 -15,3 -17,3 // Modern variant with four new pieces in randomly chosen setup on 8x8 board Game: super 8x8 6 4 5 7 3 5 4 6 6 4 5 7 3 5 4 6 p:100 -16,24 -16,6 -15,5 -17,5 p:100 16,24 16,6 15,5 17,5 k:-1 1,34 -1,34 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7 n:350 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 b:360 15,3 17,3 -15,3 -17,3 R:575 1,3 16,3 -1,3 -16,3 Q:900 1,3 16,3 15,3 17,3 -1,3 -16,3 -15,3 -17,3 S:825 15,3 17,3 -15,3 -17,3 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 E:850 1,3 16,3 -1,3 -16,3 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 V:775 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 A:1200 1,3 16,3 -1,3 -16,3 15,3 17,3 -15,3 -17,3 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 o:700 2,7 30,7 32,7 34,7 -2,7 -30,7 -32,7 -34,7 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 g:640 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7 2,7 30,7 32,7 34,7 -2,7 -30,7 -32,7 -34,7 m:-1 1,34 -1,34 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7 16,70 -16,70 w:340 1,7 16,7 -1,7 -16,7 2,7 32,7 -2,7 -32,7 // Seirawan Chess (with Archbishop and Chancellor gated in during game) Game: seirawan 8x8 5 3 4 7 6 4 3 5 5 3 4 7 6 4 3 5 p:74 -16,24 -16,6 -15,5 -17,5 p:74 16,24 16,6 15,5 17,5 n:259 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 b:296 15,3 17,3 -15,3 -17,3 R:444 1,3 16,3 -1,3 -16,3 k:-1 1,34 -1,34 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7 Q:851 1,3 16,3 15,3 17,3 -1,3 -16,3 -15,3 -17,3 k:-1 1,34 -1,34 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7 h:780 15,3 17,3 -15,3 -17,3 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 E:814 1,3 16,3 -1,3 -16,3 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 // Spartan Chess, where black has a different army from white's orthodox FIDE, with two kings Game: fairy/Spartan # PNBRQ..............K....q.lwg.....c...hk 8x8 6 4 5 7 11 5 4 6 3 10 11 8 8 11 9 3 p:74 -16,64 -16,6 -15,5 -17,5 h:70 15,E4 17,E4 16,5 15,6 17,6 l:290 15,7 17,7 -15,7 -17,7 30,7 34,7 -30,7 -34,7 1,6 -1,6 n:259 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 b:296 15,3 17,3 -15,3 -17,3 R:444 1,3 16,3 -1,3 -16,3 Q:851 1,3 16,3 15,3 17,3 -1,3 -16,3 -15,3 -17,3 c:255 1,7 16,7 -1,7 -16,7 2,7 -2,7 32,7 -32,7 w:790 15,3 17,3 -15,3 -17,3 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 G:640 1,3 16,3 -1,3 -16,3 15,7 17,7 -15,7 -17,7 k:-435 1,34 -1,34 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7 // Set for Chess with Different Armies, FIDE vs Color-bound Cloberers (legality-testing off!) Game: fairy/FIDE-Clobberers # PNBRQ.........Kp.....eac....lk 8x8 6 4 5 7 10 5 4 6 12 3 8 9 11 8 3 12 p:100 -16,24 -16,6 -15,5 -17,5 p:100 16,24 16,6 15,5 17,5 e:320 30,7 34,7 -30,7 -34,7 16,7 -16,7 1,7 -1,7 n:325 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 b:350 15,3 17,3 -15,3 -17,3 R:500 16,3 -16,3 -1,3 1,3 Q:950 1,3 16,3 15,3 17,3 -1,3 -16,3 -15,3 -17,3 c:480 15,7 17,7 -15,7 -17,7 32,7 -32,7 2,7 -2,7 30,7 34,7 -30,7 -34,7 A:875 15,3 17,3 -15,3 -17,3 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 k:-1 1,34 -1,34 1,7 -1,7 16,7 15,7 17,7 -16,7 -15,7 -17,7 k:-1 1,34 -1,1034 1,7 -1,7 16,7 15,7 17,7 -16,7 -15,7 -17,7 l:530 15,3 17,3 -15,3 -17,3 32,7 -32,7 2,7 -2,7 Game: fairy/Clobberers-FIDE # P.....EAC....LKpnbrq.........k 8x8 12 3 8 7 10 8 3 12 6 4 5 9 11 5 4 6 p:100 -16,24 -16,6 -15,5 -17,5 p:100 16,24 16,6 15,5 17,5 e:320 30,7 34,7 -30,7 -34,7 16,7 -16,7 1,7 -1,7 n:325 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 b:350 15,3 17,3 -15,3 -17,3 R:500 16,3 -16,3 -1,3 1,3 A:875 15,3 17,3 -15,3 -17,3 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 c:480 15,7 17,7 -15,7 -17,7 32,7 -32,7 2,7 -2,7 30,7 34,7 -30,7 -34,7 Q:950 1,3 16,3 15,3 17,3 -1,3 -16,3 -15,3 -17,3 k:-1 1,34 -1,1034 1,7 -1,7 16,7 15,7 17,7 -16,7 -15,7 -17,7 k:-1 1,34 -1,34 1,7 -1,7 16,7 15,7 17,7 -16,7 -15,7 -17,7 l:530 15,3 17,3 -15,3 -17,3 32,7 -32,7 2,7 -2,7 Game: fairy/FIDE-Nutters # PNBRQ................Kp...........h.t.c...uk 8x8 6 4 5 7 10 5 4 6 11 3 8 9 10 8 3 11 p:100 -16,24 -16,6 -15,5 -17,5 p:100 16,24 16,6 15,5 17,5 h:310 31,7 33,7 15,7 17,7 -31,7 -33,7 -15,7 -17,7 n:325 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 b:350 15,3 17,3 -15,3 -17,3 R:500 16,3 -16,3 -1,3 1,3 Q:950 1,3 16,3 15,3 17,3 -1,3 -16,3 -15,3 -17,3 u:400 31,7 33,7 14,7 18,7 1,7 -1,7 -16,7 -15,7 -17,7 C:935 16,3 1,3 -1,3 14,7 31,7 33,7 18,7 15,7 17,7 -16,7 -15,7 -17,7 k:-1 1,34 -1,34 1,7 -1,7 16,7 15,7 17,7 -16,7 -15,7 -17,7 t:485 16,3 1,3 -1,3 -16,7 -15,7 -17,7 Game: fairy/Nutters-FIDE # P...........H.T.C...UKpnbrq................k 8x8 11 3 6 7 10 6 3 11 8 4 5 9 10 5 4 8 p:100 -16,24 -16,6 -15,5 -17,5 p:100 16,24 16,6 15,5 17,5 h:310 31,7 33,7 15,7 17,7 -31,7 -33,7 -15,7 -17,7 n:325 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 b:350 15,3 17,3 -15,3 -17,3 u:400 -31,7 -33,7 -14,7 -18,7 1,7 -1,7 16,7 15,7 17,7 C:935 -16,3 1,3 -1,3 -14,7 -31,7 -33,7 -18,7 -15,7 -17,7 16,7 15,7 17,7 R:500 16,3 -16,3 -1,3 1,3 Q:950 1,3 16,3 15,3 17,3 -1,3 -16,3 -15,3 -17,3 k:-1 1,34 -1,34 1,7 -1,7 16,7 15,7 17,7 -16,7 -15,7 -17,7 t:485 -16,3 1,3 -1,3 16,7 15,7 17,7 Game: fairy/Clobberers-Nutters # P.....EAC....L.......Kp...........h.t.c...uk 8x8 6 4 5 7 10 5 4 6 11 3 8 9 12 8 3 11 p:100 -16,24 -16,6 -15,5 -17,5 p:100 16,24 16,6 15,5 17,5 h:310 31,7 33,7 15,7 17,7 -31,7 -33,7 -15,7 -17,7 e:320 30,7 34,7 -30,7 -34,7 16,7 -16,7 1,7 -1,7 c:480 15,7 17,7 -15,7 -17,7 32,7 -32,7 2,7 -2,7 30,7 34,7 -30,7 -34,7 l:530 15,3 17,3 -15,3 -17,3 32,7 -32,7 2,7 -2,7 A:875 15,3 17,3 -15,3 -17,3 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 u:400 31,7 33,7 14,7 18,7 1,7 -1,7 -16,7 -15,7 -17,7 C:935 16,3 1,3 -1,3 14,7 31,7 33,7 18,7 15,7 17,7 -16,7 -15,7 -17,7 k:-1 1,34 -1,1034 1,7 -1,7 16,7 15,7 17,7 -16,7 -15,7 -17,7 t:485 16,3 1,3 -1,3 -16,7 -15,7 -17,7 k:-1 1,34 -1,34 1,7 -1,7 16,7 15,7 17,7 -16,7 -15,7 -17,7 Game: fairy/Nutters-Clobberers # P...........H.T.C...UKp.....eac....l.......k 8x8 11 3 6 7 10 6 3 11 5 4 8 9 12 8 4 5 p:100 -16,24 -16,6 -15,5 -17,5 p:100 16,24 16,6 15,5 17,5 h:310 31,7 33,7 15,7 17,7 -31,7 -33,7 -15,7 -17,7 e:320 30,7 34,7 -30,7 -34,7 16,7 -16,7 1,7 -1,7 l:530 15,3 17,3 -15,3 -17,3 32,7 -32,7 2,7 -2,7 u:400 -31,7 -33,7 -14,7 -18,7 1,7 -1,7 16,7 15,7 17,7 C:935 -16,3 1,3 -1,3 -14,7 -31,7 -33,7 -18,7 -15,7 -17,7 16,7 15,7 17,7 c:480 15,7 17,7 -15,7 -17,7 32,7 -32,7 2,7 -2,7 30,7 34,7 -30,7 -34,7 A:875 15,3 17,3 -15,3 -17,3 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 k:-1 1,34 -1,34 1,7 -1,7 16,7 15,7 17,7 -16,7 -15,7 -17,7 t:485 -16,3 1,3 -1,3 16,7 15,7 17,7 k:-1 1,34 -1,1034 1,7 -1,7 16,7 15,7 17,7 -16,7 -15,7 -17,7 // Great Shatranj: modern variant with range-two leapers replacing sliders, on 10x8 board. // Must be played with legality testing off in XBoard 4.4.0. Game: great 10x8 6 4 5 8 3 10 9 5 4 6 6 4 5 8 3 10 9 5 4 6 p:100 -16,6 -15,5 -17,5 p:100 16,6 15,5 17,5 k:-1 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7 n:290 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 e:270 15,7 17,7 -15,7 -17,7 30,7 34,7 -30,7 -34,7 w:300 1,7 16,7 -1,7 -16,7 2,7 -2,7 32,7 -32,7 s:280 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7 g:640 1,7 16,7 -1,7 -16,7 2,7 -2,7 32,7 -32,7 15,7 17,7 -15,7 -17,7 30,7 34,7 -30,7 -34,7 h:640 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 15,7 17,7 -15,7 -17,7 30,7 34,7 -30,7 -34,7 m:640 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 1,7 16,7 -1,7 -16,7 2,7 -2,7 32,7 -32,7 // End of game file fairymax-4.8q/README0000644000175000017500000000163111477644744014167 0ustar vincentvincentThis package contains the sources of the XBoard-compatible Chess and Chess-variant engine Fairy-Max, and its dedicated derivatives ShaMax (for Shatranj) and MaxQi (for XiangQi = Chinese Chess). A Makefile is provided to compile and install them. Normally this would require only the command (given from the main directory of the package): sudo make install This will install the executables in /usr/games, (where XBoard expects them), and their data files in /usr/share/games/fairymax. Should you want to compile by hand, you could use the following commands: gcc -O2 fairymax.c -o fairymax gcc -O2 fairymax.c -DSHATRANJ -o shamax gcc -O2 maxqi.c -o maxqi In this case you will get versions that expect their fmax.ini or qmax.ini files in the current direcory. To change the default path of the ini files, you can include the argument -DINI_FILE=\"pathname\" to the gcc compilation command line. H.G.Muller fairymax-4.8q/Makefile0000644000175000017500000000321111477644744014743 0ustar vincentvincentsrcdir = . CC=gcc CFLAGS += -O2 ALL= fairymax shamax maxqi fairymax.6.gz all: ${ALL} fairymax: fairymax.c $(CC) $(CFLAGS) -DINI_FILE=\"/usr/share/games/fairymax/fmax.ini\" fairymax.c -o fairymax shamax: fairymax.c $(CC) $(CFLAGS) -DINI_FILE=\"/usr/share/games/fairymax/fmax.ini\" -DSHATRANJ fairymax.c -o shamax maxqi: maxqi.c $(CC) $(CFLAGS) -DINI_FILE=\"/usr/share/games/fairymax/qmax.ini\" maxqi.c -o maxqi install: ${ALL} ${srcdir}/data/* cp -u ${srcdir}/fairymax $(DESTDIR)/usr/games cp -u ${srcdir}/shamax $(DESTDIR)/usr/games cp -u ${srcdir}/maxqi $(DESTDIR)/usr/games install -d -m0755 $(DESTDIR)/usr/share/games/fairymax cp -u ${srcdir}/data/* $(DESTDIR)/usr/share/games/fairymax install -d -m0755 $(DESTDIR)/usr/share/man/man6 cp -u ${srcdir}/fairymax.6.gz $(DESTDIR)/usr/share/man/man6 fairymax.6.gz: fairymax.pod pod2man -s 6 fairymax.pod > fmax.man cp fmax.man fairymax.6 rm -f fairymax.6.gz gzip fairymax.6 clean: rm -f ${ALL} dist-clean: rm -f ${ALL} *~ data/*~ *.man md5sums dist: install -d -m0755 Fairy-Max install -d -m0755 Fairy-Max/data rm -f fairymax.tar fairymax.tar.gz cp fairymax.c maxqi.c fairymax.pod Makefile README changelog copyright Fairy-Max cp data/* Fairy-Max/data md5 Fairy-Max/* Fairy-Max/data/* > Fairy-Max/md5sums tar -cvvf fairymax.tar Fairy-Max gzip fairymax.tar rm Fairy-Max/data/* rmdir Fairy-Max/data rm Fairy-Max/* rmdir Fairy-Max uninstall: rm -f $(DESTDIR)/usr/share/games/fairymax/* rmdir $(DESTDIR)/usr/share/games/fairymax rm -f $(DESTDIR)/usr/share/man/man6/fairymax.6.gz rm -f $(DESTDIR)/usr/games/fairymax rm -f $(DESTDIR)/usr/games/shamax rm -f $(DESTDIR)/usr/games/maxqi fairymax-4.8q/maxqi.c0000644000175000017500000010401311477644744014570 0ustar vincentvincent/***************************************************************************/ /* MaxQi, */ /* Version of the sub-2KB (source) micro-Max Chess program, fused to a */ /* generic WinBoard interface, loading its move-generator tables from file */ /* Adapted to play Xiang Qi, which required rather specialized changes */ /***************************************************************************/ /* micro-Max version 4.8 (~1950 characters) features: */ /* - recursive negamax search */ /* - all-capture quiescence search with MVV/LVA priority */ /* - (internal) iterative deepening */ /* - best-move-first 'sorting' */ /* - a hash table storing score and best move */ /* - futility pruning */ /* - king safety through magnetic frozen king */ /* - null-move pruning */ /* - Late-move reductions */ /* - full FIDE rules (expt minor promotion) and move-legality checking */ /* - keep hash + rep-draw detect */ /* - end-game Pawn-push bonus, new piece values, gradual promotion */ /***************************************************************************/ /* This version reads the piece description from a file fmax.ini */ /* The format supports many fairy pieces, including hoppers. */ /* f) now supports 15 piece types, by requisitioning WHITE bit */ /* g) supports larger board width. */ /* h) castling bug ('in-check by non-captures') corrected */ /* i) rep-draw bug ('side-to-move') corrected */ /* k) allow user underpromotions, recognize & ignore 'variant' command */ /* l) edit bug corrected (i & j file clear) */ /* m) piece values no longer quantized, game-stage counting bug corrected */ /* n) edit-menu K-side castling bug corrected. */ /* o) retrieve the requested variant from the .ini file */ /* p) clear hash table on variant switch */ /* q) reduced piece-material count for better Pawn push */ /* r) hash-table bug corrected (X still ORed with flags) */ /* s) Bug that prevented initialization center points corrected */ /* t) castling bug after edit fixed */ /* u) converted to protocol 2; ping implemented */ /* v) white e.p. rights hash bug fixed; */ /* w) piece indicators programable, multi-path support */ /* x) e.p. changed to support Berolina Pawns */ /* y) capture vlue of 6-7th-rank Pawn reduced in Shatranj */ /* z) bug in promotion input corrected */ /* A) stalemate-detection bug in printResult fixed */ /* B) Invalidate hash on game-level promotion (might be under-promotion!) */ /* C) King move evaluation based on negative piece value in stead of nr */ /* D) WB memory command added, undo fixed */ /* E) 15th piece read in */ /* F) accepts ini fileargument */ /* Xiang Qi adaptations: */ /* orient board sideways for easy implementation of King-facing rule */ /* allow board to have 9 rows (= files) */ /* add array for specifying board zones */ /* add zone limiter for each piece */ /* change promotion code to act when crossing river */ /* remove stalemate code */ /* G) o[] and oo[] made int, to work on big-endian machines */ /***************************************************************************/ /*****************************************************************/ /* LICENCE NOTIFICATION */ /* Fairy-Max 4.8 is free software, and you have my permission do */ /* with it whatever you want, whether it is commercial or not. */ /* Note, however, that Fairy-Max can easily be configured through*/ /* its fmax.ini file to play Chess variants that are legally pro-*/ /* tected by patents, and that to do so would also require per- */ /* mission of the holders of such patents. No guarantees are */ /* given that Fairy-Max does anything in particular, or that it */ /* would not wreck the hardware it runs on, and running it is */ /* entirely for your own risk. H.G,Muller, author of Fairy-Max */ /*****************************************************************/ #define MULTIPATH /* fused to generic Winboard driver */ #include #include #include #include #include #ifndef WIN32 #include int GetTickCount() // with thanks to Tord { struct timeval t; gettimeofday(&t, NULL); return t.tv_sec*1000 + t.tv_usec/1000; } #ifndef INI_FILE #define INI_FILE "qmax.ini" #endif #else #include #define INI_FILE "qmax.ini" #endif int StartKey; #define EMPTY -1 #define WHITE 0 #define BLACK 16 #define STATE 128 #define FAC 128 /* 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 GameNr; char piecename[32], piecetype[32], defaultchar[]=".PPKNBRQEWFMACHG"; char *inifile = INI_FILE; int Ticks, tlim, Setup, SetupQ; int GameHistory[1024]; char HistoryBoards[1024][STATE], setupPosition[129]; int GamePtr, HistPtr; #define W while #define K(A,B) *(int*)(T+A+((B&31)<<8)) #define J(A) K(y+A,b[y])-K(x+A,u)-K(y+A,t) int U=(1<<23)-1; struct _ {int K,V;char X,Y,D,F;} *A; /* hash table, 16M+8 entries*/ int M=136,S=128,I=8e3,Q,O,K,N,j,R,J,Z,LL,L, /* M=0x88 */ BW,BH,sh, w[16]={0,2,2,-1,7,8,12,23,7,5}, /* relative piece values */ o[256], oo[32], /* initial piece setup */ of[256], od[16]; /* 1st dir. in o[] per piece*/ signed char b[513], /* board: 16x8+dummy, + PST */ T[8200], /* hash translation table */ centr[32], n[]=".P*KEEQQAHCR????x+pkeeqqahcr????"; /* piece symbols on printout*/ char zn[] = { /* zones of xiangqi board */ 1,1,1,1,1,2,2,2,2,2, 0,0,0,0,0,0, 1,1,1,1,1,2,2,2,2,2, 0,0,0,0,0,0, 1,1,1,1,1,2,2,2,2,2, 0,0,0,0,0,0, 0,0,0,1,1,2,2,0,0,0, 0,0,0,0,0,0, 0,0,0,1,1,2,2,0,0,0, 0,0,0,0,0,0, 0,0,0,1,1,2,2,0,0,0, 0,0,0,0,0,0, 1,1,1,1,1,2,2,2,2,2, 0,0,0,0,0,0, 1,1,1,1,1,2,2,2,2,2, 0,0,0,0,0,0, 1,1,1,1,1,2,2,2,2,2, 0,0,0,0,0,0 }; pboard() {int i; i=-1;W(++i<144)printf(" %c",(i&15)==BW&&(i+=15-BW)?10:n[b[i]&31]); } D(k,q,l,e,z,n) /* recursive minimax search, k=moving side, n=depth*/ int k,q,l,e,z,n; /* (q,l)=window, e=current eval. score, E=e.p. sqr.*/ { /* e=score, z=prev.dest; J,Z=hashkeys; return score*/ int j,r,m,v,d,h,i,P,V,f=J,g=Z,C,s,flag,F; unsigned char t,p,u,x,y,X,Y,B,lu; struct _*a=A+(J+k&U-1); /* lookup pos. in hash table*/ q-=qD;m=a->V;F=a->F; /* resume at stored depth */ X=a->X;Y=a->Y; /* start at best-move hint */ if(z&S&&a->K==Z)printf("# root hit %d %d %x\n",a->D,a->V,a->F); if(a->K-Z|z&S | /* miss: other pos. or empty*/ !(m<=q|F&8&&m>=l|F&S)) /* or window incompatible */ d=X=0,Y=-1; /* start iter. from scratch */ W(d++2&&l+I?D(16-k,-l,1-l,-e,2*S,d-3):I; /* search null move */ m=-P beta unconsidered:static eval */ N++; /* node count (for timing) */ do{u=b[x]; /* scan board looking for */ if(u)m=lu|u&15^3?m:(d=98,I),lu=u&15^3; /* Kings facing each other */ if(u&&(u&16)==k) /* own piece (inefficient!)*/ {r=p=u&15; /* p = piece type (set r>0) */ j=od[p]; /* first step vector f.piece*/ W(r=o[++j]) /* loop over directions o[] */ {A: /* resume normal after best */ flag=h?3:of[j]; /* move modes (for fairies) */ y=x; /* (x,y)=move */ do{ /* y traverses ray, or: */ y=h?Y:y+r; /* sneak in prev. best move */ if(y>=16*BH|(y&15)>=BW)break; /* board edge hit */ t=b[y]; /* captured piece */ if(flag&1+!t) /* mode (capt/nonc) allowed?*/ {if(t&&(t&16)==k||flag>>10&zn[y])break; /* capture own or bad zone */ i=w[t&15]; /* value of capt. piece t */ if(i<0)m=I,d=98; /* K capture */ if(m>=l&d>1)goto C; /* abort on fail high */ v=d-1?e:i-p; /*** MVV/LVA scoring if d=1**/ if(d-!t>1) /*** all captures if d=2 ***/ {v=centr[p]?b[x+257]-b[y+257]:0; /* center positional pts. */ b[x]=0;b[y]=u; /* do move */ v-=w[p]>0|R<10?0:20; /*** freeze K in mid-game ***/ if(p<3) /* pawns: */ {v+=2; /* end-game Pawn-push bonus */ if(zn[x]-zn[y])b[y]+=5, /* upgrade Pawn and */ i+=w[p+5]-w[p]; /* promotion bonus */ } if(z&S && GamePtr<6) v+=(rand()>>10&31)-16; // randomize in root J+=J(0);Z+=J(4); v+=e+i;V=m>q?m:q; /*** new eval & alpha ****/ C=d-1-(d>5&p>2&!t&!h); /* nw depth, reduce non-cpt.*/ C=R<10|P-I|d<3||t&&p-3?C:d; /* extend 1 ply if in-check */ do s=C>2|v>V?-D(16-k,-l,-V,-v,/*** futility, recursive eval. of reply */ 0,C):v; W(s>q&++CD=99;a->V=500; /* lock game in hash as loss*/ R-=i/FAC; /*** total captd material ***/ Fifty = t|p<3?0:Fifty+1; return l;} /* & not in check, signal */ v=m; /* (prevent fail-lows on */ } /* K-capt. replies) */ J=f;Z=g; b[y]=t;b[x]=u; /* undo move */ } /* if non-castling */ if(v>m) /* new best, update max,best*/ m=v,X=x,Y=y; /* no marking! */ if(h){h=0;goto A;} /* redo after doing old best*/ } s=t; t+=flag&4; /* fake capt. for nonsliding*/ if(s&&flag&8)t=0,flag^=flag>>4&15; /* hoppers go to next phase */ if(!(flag&S)) /* zig-zag piece? */ r^=flag>>12,flag^=flag>>4&15; /* alternate vector & mode */ }W(!t); /* if not capt. continue ray*/ }} if((++x&15)>=BW)x=x+16&240,lu=1; /* next sqr. of board, wrap */ if(x>=16*BH)x=0; }W(x-B); C:if(a->D<99) /* protect game history */ a->K=Z,a->V=m,a->D=d,a->X=X, /* always store in hash tab */ a->F=8*(m>q)|S*(mY=Y; /* move, type (bound/exact),*/ if(z&S&&Post){ printf("%2d ",d-2); printf("%6d ",m); printf("%8d %10d %c%c%c%c\n",(GetTickCount()-Ticks)/10,N, 'i'-(X>>4&15),'9'-(X&15),'i'-(Y>>4&15),'9'-(Y&15)),fflush(stdout);} } /* encoded in X S,8 bits */ if(z&4*S)K=X,L=Y&~S; return m+=m 1) /* third repeat */ { printf("1/2-1/2 {Draw by repetition}\n"); return 1; } differs: ; } K=I; cnt = D(s,-I,I,Q,4*S,3); if(cnt==-I+1) { if (s == WHITE) printf("0-1 {Black mates}\n"); else printf("1-0 {White mates}\n"); return 3; } if(Fifty >=100) { printf("1/2-1/2 {Draw by fifty move rule}\n"); return 4; } return 0; } InitEngine() { int i, j; N=8100;W(N-->256)T[N]=rand()>>9; srand(GetTickCount()); } InitGame() { int i,j; for(i=0;i<16*BH;i++)b[i]=0; /* clear board */ b[23]=b[119]=10;b[BW+8]=b[BW+104]=26; /* place Cannons */ K=BH;W(K--) {b[16*K]=oo[K+16]+16;b[16*K+BW-1]=oo[K];if(!(K&1))b[16*K+BW-7]=18,b[16*K+6]=1; /* initial board setup*/ L=BW;W(L--)b[L+16*K+257]=(K-(BW-1)/2.)*(K-(BW-1)/2.)+(L-(BH-1)/2.)*(L-(BH-1)/2.); /* center-pts table */ } /*(in unused half b[])*/ Side = WHITE; Q=0; O=S; Fifty = 0; R = 0; for(i=0; i12 || BH>9) { printf("telluser unsupported board size %dx%d\n",BW,BH); exit(0); } for(i=0; i='a'; piecetype[c&31]=i; piecename[i]=c&31; } j++; o[j]=0; /* printf("tell c='%c' i=%d od[i]=%d j=%d (%3d,%8x)\n",c,i,od[i],j,o[j-1],of[j-1]); /**/ c=0; if(i>15 || j>255) break; } fclose(f); sh = w[7] < 250 ? 3 : 0; } int main(int argc, char **argv) { int Computer, MaxTime, MaxMoves, TimeInc, sec, i, j; char line[256], command[256], c, cc; int m, nr; FILE *f; if(argc>1 && sscanf(argv[1], "%d", &m)==1) { U = (1<1) inifile = argv[1]; signal(SIGINT, SIG_IGN); printf("tellics say MaxQi 4.8 (G)\n"); printf("tellics say by H.G. Muller\n"); InitEngine(); LoadGame(NULL); InitGame(); Computer = EMPTY; MaxTime = 10000; /* 10 sec */ MaxDepth = 30; /* 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.6-0.06*(BW-8))*(TimeLeft+(m-1)*TimeInc)/(m+7); if(tlim>TimeLeft/15) tlim = TimeLeft/15; PromPiece = 0; /* Always promote to Queen ourselves */ N=0;K=I; if (D(Side,-I,I,Q,S,3)==I) { Side ^= BLACK^WHITE; if(UnderProm>=0 && UnderProm != L) { printf("tellics I hate under-promotions!\n"); printf("resign { underpromotion } \n"); Computer = EMPTY; continue; } else UnderProm = -1; printf("move "); printf("%c%c%c%c",'i'-(K>>4),'9'-(K&15), 'i'-(L>>4&15),'9'-(L&15)); printf("\n"); m = GetTickCount() - Ticks; /* 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 { refuses own move }\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, "protover")) { printf("feature myname=\"MaxQi 4.8G\"\n"); printf("feature memory=1\n"); printf("feature smp=1\n"); printf("feature setboard=0 ping=1 done=0\n"); printf("feature variants=\""); PrintVariants(); printf("\" done=1\n"); continue; } if (!strcmp(command, "ping")) { int nr=0; sscanf(line, "ping %d", &nr); printf("pong %d\n", nr); continue; } if (!strcmp(command, "p")) { pboard(); continue; } if (!strcmp(command, "memory")) { int mem, mask; sscanf(line+6, "%d", &mem); mem = (mem*1024*1024)/12; // max nr of hash entries mask = 0x7FFFFFFF; while(mask > mem) mask >>= 1; if(mask != U) { free(A); U = mask; A = (struct _ *) calloc(U+1, sizeof(struct _)); } continue; } if (!strcmp(command, "new")) { /* start new game */ LoadGame("xiangqi"); InitGame(); GamePtr = Setup = 0; GameNr++; 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,4*S,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 < 0) continue; GamePtr -= nr; HistPtr -= nr; /* erase history boards */ while(nr-- > 0) for(m=0; m= 'A' && m <= 'Z' && line[1] >= 'a' && line[1] <= 'a'+BH-1 && line[2] >= '0' && line[2] <= '0'+BW-1) { m = 16*('i'-line[1])+'9'-line[2]; p = 4; /* Elephant code */ switch(line[0]) { case 'K': b[m]=3+color; break; case 'R': p++; case 'C': p++; case 'H': p++; case 'A': p+=4; b[m]=p+color; Q+=w[p]; R+=w[p]/FAC; break; case 'P': if((color==WHITE) == ((m&15)<5)) p = 6; else p = 1; case 'E': p+=(color==BLACK); b[m]=p+color; Q+=w[p]; R+=w[p]/FAC; break; } continue; } } if(Side != color) Q = -Q; GamePtr = HistPtr = 0; Setup = 1; SetupQ = Q; // start anew for(i=0; i<128; i++) setupPosition[i] = b[i]; // remember position setupPosition[128] = Side; continue; } /* command not recognized, assume input move */ m = line[0]<'a' | line[0]>='a'+BH | line[1]<'0' | line[1]>='0'+BW | line[2]<'a' | line[2]>='a'+BH | line[3]<'0' | line[3]>='0'+BW | line[4] != '\n'; {char *c=line; K=16*('i'-c[0])+'9'-c[1]; L=16*('i'-c[2])+'9'-c[3]; } if (m) /* doesn't have move syntax */ printf("Error (unknown command): %s\n", command); else if(D(Side,-I,I,Q,S,3)!=I) { /* did have move syntax, but illegal move */ printf("Illegal move:%s\n", line); } else { /* legal move, perform it */ GameHistory[GamePtr++] = PACK_MOVE; Side ^= BLACK^WHITE; CopyBoard(HistPtr=HistPtr+1&1023); if(PrintResult(Side)) Computer = EMPTY; } } }