Better implementation of Seirawan Chess
authorH.G. Muller <h.g.muller@hccnet.nl>
Wed, 1 Dec 2010 16:12:27 +0000 (17:12 +0100)
committerH.G. Muller <h.g.muller@hccnet.nl>
Thu, 2 Dec 2010 12:39:22 +0000 (13:39 +0100)
The previous implementation gated 'blindly', without gating being
considered in the search. Now the gating is put in the search, by
assigning the variable gt (initialized to 0) to the from square in
stead of a straight 0 (= empty square), when making the move. An extra
loop (alas, goto-based) then steps gt through the available pieces
(removing and putting them back into the holdings) when the moved piece
is a virgin non-Pawn and the variant allows gating.
  In the root the value of gt for the best move is remembered in the
global variable GT, while searching (i.e. K==I). This can also be set
from the promoChar of an input move. The pass to perform the move (with
K != I) then compares gt to GT when testing for legality.

fix

data/fmax.ini
fairymax.c

index 1c1a6db..5e006c2 100644 (file)
@@ -415,17 +415,18 @@ d:625 1,7 16,7 -1,7 -16,7 15,3 17,3 -15,3 -17,3
 // Seirawan Chess (with Archbishop and Chancellor gated in during game)\r
 Game: seirawan\r
 8x8\r
-5 3 4 7 9 4 3 5\r
-5 3 4 7 9 4 3 5\r
+5 3 4 7 6 4 3 5\r
+5 3 4 7 6 4 3 5\r
 p:74 -16,24 -16,6 -15,5 -17,5 \r
 p:74  16,24 16,6 15,5 17,5\r
 n:259 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7\r
 b:296 15,3 17,3 -15,3 -17,3\r
 R:444 1,3 16,3 -1,3 -16,3\r
-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\r
+k:-1  1,34 -1,34 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7\r
 Q:851 1,3 16,3 15,3 17,3 -1,3 -16,3 -15,3 -17,3\r
-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\r
 k:-1  1,34 -1,34 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7\r
+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\r
+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\r
 \r
 // Spartan Chess, where black has a different army from white's orthodox FIDE, with two kings\r
 Game: fairy/Spartan # PNBRQ..............K....q.lwg.....c...hk\r
index 0f4dd5f..c135fb6 100644 (file)
@@ -111,7 +111,7 @@ int GamePtr, HistPtr;
 int U=(1<<23)-1;\r
 struct _ {int K,V;char X,Y,D,F;} *A;           /* hash table, 16M+8 entries*/\r
 \r
-int M=136,S=128,I=8e3,Q,O,K,N,j,R,J,Z,LL,      /* M=0x88                   */\r
+int M=136,S=128,I=8e3,Q,O,K,N,j,R,J,Z,LL,GT,   /* M=0x88                   */\r
 BW,BH,sh,\r
 w[16]={0,2,2,-1,7,8,12,23,7,5},                /* relative piece values    */\r
 o[256],\r
@@ -138,7 +138,7 @@ 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.*/\r
 {                       /* e=score, z=prev.dest; J,Z=hashkeys; return score*/\r
  int j,r,m,v,d,h,i,F,G,P,V,f=J,g=Z,C,s,flag,FF,*ps=sp,kk=S;\r
- signed char t,p,u,x,y,X,Y,H,B;\r
+ signed char t,p,u,x,y,X,Y,H,B,gt;\r
  struct _*a=A+(J+(k+S)*E&U-1);                 /* lookup pos. in hash table*/\r
  *sp++=0;\r
  q-=q<e;l-=l<=e;                               /* adj. window: delay bonus */\r
@@ -186,9 +186,10 @@ int k,q,l,e,E,z,n;      /* (q,l)=window, e=current eval. score, E=e.p. sqr.*/
        if(m>=l&d>1)goto C;                     /* abort on fail high       */\r
        v=d-1?e:i-p;                            /*** MVV/LVA scoring if d=1**/\r
        if(d-!t>1)                              /*** all captures if d=2  ***/\r
-       {v=centr[p]?b[x+257]-b[y+257]:0;        /* center positional pts.   */\r
+       {v=gt=0;G:                              /* retry move with gating   */\r
+        v+=centr[p]?b[x+257]-b[y+257]:0;       /* center positional pts.   */\r
         if(!(G&S))b[FF]=b[G],v+=50;            /* castling: put R & score  */\r
-        b[G]=b[H]=b[x]=0;b[y]=u|32;            /* do move, set non-virgin  */\r
+        b[G]=b[H]=0;b[x]=gt;b[y]=u|32;         /* do move, set non-virgin  */\r
         pl[t&31]-=!!t;                         /* updat victim piece count */\r
         v-=w[p]>0|R<EG?0:20;                   /*** freeze K in mid-game ***/\r
         if(p<3)                                /* pawns:                   */\r
@@ -217,33 +218,39 @@ int k,q,l,e,E,z,n;      /* (q,l)=window, e=current eval. score, E=e.p. sqr.*/
          *ps=256*x+y;\r
         }\r
         if(z&S&&K-I)                           /* move pending: check legal*/\r
-        {if(v+I&&x==K&y==L)                    /*   if move found          */\r
-         {Q=-e-i;O=F;LL=L;prom=0;\r
+        {if(v+I&&x==K&y==L&gt==GT)             /*   if move found          */\r
+         {Q=-e-i;O=F;LL=L;prom=gt;\r
           if(b[y]-u&15)prom=b[y]-=PromPiece,   /* under-promotion, correct */\r
                        J+=PromPiece;           /*  piece & invalidate hash */\r
           a->D=99;a->V=0;                      /* lock game in hash as draw*/\r
           R-=i/FAC;                            /*** total captd material ***/\r
           Fifty = t|p<3?0:Fifty+1;\r
           sp=ps;\r
-          if(!(u&32)&PromPiece&(K&112)==(k?0:112))\r
-           prom=b[K]=39+k-PromPiece,J+=333,pl[k+14-PromPiece]--; /* gating    */\r
                      return l;}                /*   & not in check, signal */\r
          v=m;                                  /* (prevent fail-lows on    */\r
         }                                      /*   K-capt. replies)       */\r
-        J=f;Z=g;\r
         SHAMAX( pl[k]+=!!t; ) pl[t&31]+=!!t;\r
         b[G]=b[FF];b[FF]=b[y]=0;b[x]=u;b[H]=t; /* undo move,G can be dummy */\r
        }                                       /*          if non-castling */\r
-       if(z&S&&Post&K==I&d>2&v>V&v<l){int *p=ps;char X,Y;\r
-        printf("%2d ",d-2);\r
-        printf("%6d ",v);\r
-        printf("%8d %10d",(GetTickCount()-Ticks)/10,N);\r
-        while(*p){X=*p>>8;Y=*p++;\r
-        printf(" %c%c%c%c",'a'+(X&15),'8'-(X>>4),'a'+(Y&15),'8'-(Y>>4&7));}\r
-        printf("\n");fflush(stdout);\r
+       if(z&S&&K==I&d>2&v>V&v<l){int *p=ps;char X,Y;\r
+        if(Post){\r
+         printf("%2d ",d-2);\r
+         printf("%6d ",v);\r
+         printf("%8d %10d",(GetTickCount()-Ticks)/10,N);\r
+         while(*p){X=*p>>8;Y=*p++;\r
+         printf(" %c%c%c%c",'a'+(X&15),'8'-(X>>4),'a'+(Y&15),'8'-(Y>>4&7));}\r
+         printf("\n");fflush(stdout);\r
+        }GT=gt;                                /* In root, remember gated  */\r
        }\r
        if(v>m)                                 /* new best, update max,best*/\r
         m=v,X=x,Y=y|S&F;                       /* mark non-double with S   */\r
+       if(gating&&!(u&32)&&p>2&&d-!t>1){       /* virgin non-Pawn: gate    */\r
+        pl[(gt|=k+40)-27]++;                   /* prev. gated back in hand */\r
+        if(m>=l)goto C;                        /* loop skips cutoff :-(    */\r
+        W(++gt<k+43)if(pl[gt-27]){             /* look if more to gate     */\r
+         pl[gt-27]--;v=10;goto G;              /* remove from hand & retry */\r
+       }}\r
+       J=f;Z=g;\r
        if(h){h=0;goto A;}                      /* redo after doing old best*/\r
       }\r
       s=t;v=r^flag>>12;                        /* calc. alternated vector  */\r
@@ -389,7 +396,7 @@ InitGame()
  R -= 2*(-k/FAC);\r
  UnderProm = -1; pl[WHITE] = pl[BLACK] = 2*BW; \r
  pm = !pl[BLACK+7] && pl[BLACK+9] && pl[WHITE+7] ? 2 : 0; // Unlike white, black has no 'Q', so promote to 9, which he does have.\r
- if(gating) pl[13] = pl[15] = pl[29] = pl[31] = 1, R += 2*(w[6]/FAC + w[8]/FAC);\r
+ if(gating) pl[14] = pl[15] = pl[30] = pl[31] = 1, R += 2*(w[9]/FAC + w[10]/FAC);\r
 }\r
 \r
 void CopyBoard(int s)\r
@@ -455,10 +462,10 @@ int LoadGame(char *name)
         if(fscanf(f, "version 4.8(%c)", &c)!=1 || c != 'w')\r
         { printf("telluser incompatible fmax.ini file\n"); exit(0); }\r
 \r
-        gating = 0;
+        gating = 0;\r
         if(name != NULL)\r
         {  /* search for game name in definition file */\r
-           if(!strcmp(name, "fairy")) name = selectedFairy;
+           if(!strcmp(name, "fairy")) name = selectedFairy;\r
            gating = !strcmp(name, "seirawan");\r
            while((ptc=fscanf(f, "Game: %s # %s", buf, pieceToChar))==0 || strcmp(name, buf) ) {\r
                while((c = fgetc(f)) != EOF && c != '\n');\r
@@ -549,12 +556,9 @@ int main(int argc, char **argv)
                         tlim = (0.6-0.06*(BW-8))*(TimeLeft+(m-1)*TimeInc)/(m+7);\r
                         if(tlim>TimeLeft/15) tlim = TimeLeft/15;\r
                         PromPiece = 0; /* Always promote to Queen ourselves */\r
-                        if(pl[Side+13])PromPiece=1;else if(pl[Side+15])PromPiece=-1; /* S-Chess gating */\r
                         N=0;K=I;\r
                         if (D(Side,-I,I,Q,O,LL|S,3)==I) {\r
                             Side ^= BLACK^WHITE;\r
-                            if(b[K]&&Score+D(Side,-I,I,Q,2*S,2*S,2)>S)\r
-                                prom=b[K]=0,J-=333,pl[30-Side-PromPiece]++; /* undo bad gating */\r
                             if(UnderProm>=0 && UnderProm != L)\r
                             {    printf("tellics I hate under-promotions!\n");\r
                                  printf("resign { underpromotion } \n");\r
@@ -853,8 +857,8 @@ int main(int argc, char **argv)
                 m = line[0]<'a' | line[0]>='a'+BW | line[1]<'1' | line[1]>='1'+BH |\r
                     line[2]<'a' | line[2]>='a'+BW | line[3]<'1' | line[3]>='1'+BH;\r
                 if(line[4] == '\n') line[4] = 0;\r
-                PromPiece = (Side == WHITE ? piecetype : blacktype)[line[4]&31];\r
-                if(PromPiece) PromPiece = (Side == WHITE ? 7 : 7+pm) - PromPiece;\r
+                GT = (Side == WHITE ? piecetype : blacktype)[line[4]&31];\r
+                if(GT) PromPiece = (Side == WHITE ? 7 : 7+pm) - GT, GT |= 32 + Side;\r
                 {char *c=line; K=c[0]-16*c[1]+799;L=c[2]-16*c[3]+799; }\r
                 if (m)\r
                         /* doesn't have move syntax */\r
@@ -862,10 +866,11 @@ int main(int argc, char **argv)
                 else { int i=-1;\r
                     if(b[L] && (b[L]&16) == Side && w[b[L]&15] < 0) // capture own King: castling\r
                     { i=K; K = L; L = i>L ? i-1 : i+2; }\r
+                    if(b[K]&32) GT = 0; // non-virgin mover => true promotion rather than gating\r
                     if(D(Side,-I,I,Q,O,LL|S,3)!=I) {\r
                         /* did have move syntax, but illegal move */\r
                         printf("Illegal move:%s\n", line);\r
-                    } else {  /* legal move, perform it */
+                    } else {  /* legal move, perform it */\r
                         if(i >= 0) b[i]=b[K],b[K]=0; // reverse Seirawan gating\r
                         GameHistory[GamePtr++] = PACK_MOVE;\r
                         Side ^= BLACK^WHITE;\r