Discount score when mating potential in jeopardy
authorH.G. Muller <h.g.muller@hccnet.nl>
Mon, 11 Feb 2013 22:00:22 +0000 (23:00 +0100)
committerH.G. Muller <h.g.muller@hccnet.nl>
Wed, 13 Feb 2013 22:14:10 +0000 (23:14 +0100)
A new routine is added to the search, to determine the right-shift of
the score when the leading side does nor have mating potential, its last
Pawn is in jeopardy and no mating potential will be left, or when it has
no Pawns to begin with (even with mating potential). The heuristic for
mating potential can be fine-tuned by hiding some flags in the pair bonus
field, for 'mating minor', 'deficient pair' or 'tough defender'.

fairymax.c

index 54bcf60..bdb76e4 100644 (file)
@@ -124,7 +124,7 @@ struct _ {int K,V;char X,Y,D,F;} *A;           /* hash table, 16M+8 entries*/
 \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
+w[32]={0,2,2,-1,7,8,12,23,7,5},                /* relative piece values    */\r
 o[256],\r
 oo[32],                                        /* initial piece setup      */\r
 of[256],\r
@@ -145,14 +145,14 @@ void pboard()
 }\r
          \r
 \r
-D(k,q,l,e,E,z,n)        /* recursive minimax search, k=moving side, n=depth*/\r
-int k,q,l,e,E,z,n;      /* (q,l)=window, e=current eval. score, E=e.p. sqr.*/\r
+D(k,q,l,e,ev,E,z,n)      /* recursive minimax search, k=moving side, n=depth*/\r
+int k,q,l,e,ev,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
+ int j,r,m,v,d,h,i,F,G,P,V,f=J,g=Z,C,s,flag,FF,*ps=sp,kk=S,re;\r
  signed char t,p,u,x,y,X,Y,H,B,gt;\r
  struct _*a=A+(J+(k+S)*E&U);                   /* lookup pos. in hash table*/\r
  *sp++=0;\r
- q-=q<e;l-=l<=e;                               /* adj. window: delay bonus */\r
+ q-=q<ev;l-=l<=ev;                             /* adj. window: delay bonus */\r
  d=a->D;m=a->V;X=a->F;Y=a->Y;                  /* resume at stored depth   */\r
  if(a->K-Z|z&S  |                              /* miss: other pos. or empty*/\r
   !(m<=q|X&8&&m>=l|X&S))                       /*   or window incompatible */\r
@@ -163,8 +163,8 @@ int k,q,l,e,E,z,n;      /* (q,l)=window, e=current eval. score, E=e.p. sqr.*/
    (K=X,L=Y&~S,Score=m,d=3)))                  /* time's up: go do best    */\r
  {x=B=X;                                       /* start scan at prev. best */\r
   h=Y&S;                                       /* request try noncastl. 1st*/\r
-  P=d>2&&l+I?D(16-k,-l,1-l,-e,2*S,2*S,d-3):I;  /* search null move         */\r
-  m=-P<l|R<5?d-2?-I:e:-P;   /*** prune if > beta  unconsidered:static eval */\r
+  P=d>2&&l+I?D(16-k,-l,1-l,-e,-ev,2*S,2*S,d-3):I;  /* search null move     */\r
+  m=-P<l|R<5?d-2?-I:ev:-P;  /*** prune if > beta  unconsidered:static eval */\r
   SHAMAX( if(pl[k]<=1&pl[16-k]>1)m=I-1; )      /* bare king loses          */\r
   N++;                                         /* node count (for timing)  */\r
   do{u=b[x];                                   /* scan board looking for   */\r
@@ -195,7 +195,7 @@ int k,q,l,e,E,z,n;      /* (q,l)=window, e=current eval. score, E=e.p. sqr.*/
        if(i<0&&(pl[t&31]<2||                   /* K capture, (of last K),  */\r
         t>>3&kk!=H&kk!=S||(kk=H,i=-i,0)))m=I,d=98;/* or duple check: cutoff*/\r
        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
+       v=d-1?ev:i-p;                           /*** MVV/LVA scoring if d=1**/\r
        if(d-!t>1)                              /*** all captures if d=2  ***/\r
        {v=gt=0;G:                              /* retry move with gating   */\r
         v+=centr[p]?b[x+257]-b[y+257]:0;       /* center positional pts.   */\r
@@ -216,12 +216,13 @@ int k,q,l,e,E,z,n;      /* (q,l)=window, e=current eval. score, E=e.p. sqr.*/
         J+=J(0);Z+=J(4)+G-S;\r
         pl[k]-=!!t;                            /* count pieces per side    */\r
         v+=e+i;V=m>q?m:q;                      /*** new eval & alpha    ****/\r
+        re=v>>Fac(v>>15&16^k);  /* Reduce eval if drawish for leading side */\r
         if(z&S)V=m-margin>q?m-margin:q;        /* multiPV                  */\r
         C=d-1-(d>5&p>2&!t&!h);                 /* nw depth, reduce non-cpt.*/\r
         C=R<EG|P-I|d<3||t&&p-3?C:d;            /* extend 1 ply if in-check */\r
         do\r
-         s=C>2|v>V?-D(16-k,-l,-V,-v,/*** futility, recursive eval. of reply */\r
-                                     F,y&255,C):v;\r
+         s=C>2|re>V?-D(16-k,-l,-V,/*** futility, recursive eval. of reply */\r
+                                  -v,-re,F,y&255,C):re;\r
         W(s>q&++C<d); v=s;                     /* no fail:re-srch unreduced*/\r
         if(v>V&v<l){int *p=sp;\r
          sp=ps+1;\r
@@ -285,9 +286,33 @@ C:FMAX( m=m+I|P==I?m:(X=Y=0); )                /* if stalemate, draw-score */
   }                                            /*    encoded in X S,8 bits */\r
 if(z&4*S)K=X,L=Y&~S;\r
  sp=ps;\r
- return m+=m<e;                                /* delayed-loss bonus       */\r
+ return m+=m<ev;                               /* delayed-loss bonus       */\r
 }\r
 \r
+Fac(int k)\r
+{/* if mating potential in jeopardy, indicate score reduction (as shift)   */\r
+ int m,h,i,j,e,f=0,r=0,n=pl[k+1]+pl[k+2];      /* k indicates strong side  */\r
+ if(n<2){                                      /* less than 2 pawns        */\r
+  r=1-n;                                       /* reduce by 2 if no pawns  */\r
+  m=pl[16-k]-n;                                /* my pieces (incl. King)   */\r
+  if(m<4){                                     /* we have at most 2 pieces */\r
+   h=pl[k]-pl[17-k]-pl[18-k];                  /* his pieces (incl. King)  */\r
+   if(h<2)r=0;                                 /* bare K easy even w.o. P  */\r
+   j=h-n;                                      /* defenders after sac for P*/\r
+   if(j<3&&j--){                               /* can sac, <= 1 piece left */\r
+    i=18-k;W(!pl[++i]);                        /* get lowest piece         */\r
+    e=abs(w[i--])*n;                           /* sac for Pawn (if any)    */\r
+    W(h>1)h-=pl[++i],e-=pl[i]*w[i];            /* total value his remaining*/\r
+    if(!h)e+=3*w[i];                           /* dual King, correct w[]<0 */\r
+    j&=pb[i]==-1;                              /* tough defenders left     */\r
+    for(i=k+3,h=m;h>1;h-=pl[i++])e+=pl[i]*w[i],/* lead in piece material   */\r
+     f|=pl[i]&pb[i]/*,printf("%d,%d,%d=%d,%d ",i,pl[i],pb[i],e,f)*/;                           /* detect mating minors     */\r
+    if(!f&&e<350                               /* non-mating minor ahead   */\r
+     ||m-1&(pb[--i]>3|j)                 /* single color-bound or vs tough */\r
+     ||pl[i]==2&pb[i]<-1)r=3-n;                /* non-mating pair          */\r
+ }}}\r
+ return r;\r
+}\r
 \r
 /* Generic main() for Winboard-compatible engine     */\r
 /* (Inspired by TSCP)                                */\r
@@ -342,7 +367,7 @@ int PrintResult(int s)
           differs: ;\r
         }\r
         K=I;\r
-        cnt = D(s,-I,I,Q,O,LL|4*S,3);\r
+        cnt = D(s,-I,I,Q,Q,O,LL|4*S,3);\r
 #ifdef SHATRANJ\r
         if(pl[s]==1 && pl[16-s]==1) {\r
                 printf("1/2-1/2 {Insufficient mating material}\n");\r
@@ -509,7 +534,7 @@ void LoadGame(char *name)
         while(fscanf(f, "%d,%x", o+j, of+j)==2 ||\r
                                       fscanf(f,"%c:%d",&c, w+i+1)==2)\r
         {   if(c)\r
-            { od[++i]=j; centr[i] = c>='a';\r
+            { od[++i]=j; centr[i] = c>='a'; w[i+16] = w[i];\r
               blacktype[c&31]=i; piecename[i]=c&31;\r
               if(piecetype[c&31]==0) piecetype[c&31]=i; // only first\r
               pb[i] = pb[i+16] = w[i]>>3 & ~3; // pair bonus, for now 1/8 of piece value, leave low bits for flag\r
@@ -579,7 +604,7 @@ int main(int argc, char **argv)
                         if(tlim>TimeLeft/15) tlim = TimeLeft/15;\r
                         PromPiece = 0; /* Always promote to Queen ourselves */\r
                         N=0;K=I;\r
-                        if (D(Side,-I,I,Q,O,LL|S,3)==I) {\r
+                        if (D(Side,-I,I,Q,Q,O,LL|S,3)==I) {\r
                             Side ^= BLACK^WHITE;\r
                             m = GetTickCount() - Ticks;\r
                             printf("# times @ %u: real=%d cpu=%1.0f\n", m + Ticks, m,\r
@@ -763,7 +788,7 @@ int main(int argc, char **argv)
                }\r
                if (!strcmp(command, "hint")) {\r
                         Ticks = GetTickCount(); tlim = 1000;\r
-                        D(Side,-I,I,Q,O,LL|4*S,6);\r
+                        D(Side,-I,I,Q,Q,O,LL|4*S,6);\r
                         if (K==0 && L==0)\r
                                continue;\r
                         printf("Hint: ");\r
@@ -793,7 +818,7 @@ int main(int argc, char **argv)
                        for(i=0; i<=U; i++) A[i].D = A[i].K = 0; // clear hash table\r
                         for(nr=0; nr<GamePtr; nr++) {\r
                             UNPACK_MOVE(GameHistory[nr]);\r
-                            D(Side,-I,I,Q,O,LL|S,3);\r
+                            D(Side,-I,I,Q,Q,O,LL|S,3);\r
                             Side ^= BLACK^WHITE;\r
                         }\r
                        continue;\r
@@ -892,7 +917,7 @@ int main(int argc, char **argv)
                     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]&15) < 3) GT = 0; // Pawn => true promotion rather than gating\r
-                    if(D(Side,-I,I,Q,O,LL|S,3)!=I) {\r
+                    if(D(Side,-I,I,Q,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 */\r