Prune futile interpositions at d <= 1
authorH.G.Muller <hgm@hgm-xboard.(none)>
Sat, 14 Jan 2017 17:50:56 +0000 (18:50 +0100)
committerH.G.Muller <hgm@hgm-xboard.(none)>
Sat, 14 Jan 2017 17:50:56 +0000 (18:50 +0100)
A variable ipMask records squares attacked by board moves along the
check ray, immediately after move generation. Evasion drops are then
limited only to such squares, at depth <= 1.

dropper.c

index e5883d2..825e6b9 100644 (file)
--- a/dropper.c
+++ b/dropper.c
@@ -851,11 +851,12 @@ CheckDrops (int stm, int king)
 }
 
 void
-EvasionDrops (int stm, StackFrame *f)
+EvasionDrops (int stm, StackFrame *f, int mask)
 {
     int i, x = f->checker, v = f->checkDir, s = stm ^ COLOR;
     while(board[x+=v] == 0) { // all squares on check ray
        int last = maxDrop;
+       if((mask >>= 1) & 1) continue; // suppress 'futile interpositions'
        i = zoneTab[x] & Z_LAST; // Pawn not on first & last rank (OK for zh)
        if(perpLoses) { // but it is Shogi!
            if(!(zoneTab[x] & stm)) i = 0; // outside zone, so dropping is always allowed
@@ -945,6 +946,14 @@ Pinned (int stm, int fromSqr, int xking)
 }
 
 int
+SafeIP (StackFrame *f)
+{   // figure out which squares are protected on the check ray
+    int result = 0, v = f->checkDir, x = f->checker, mask = 1;
+    while(board[x+=v] == 0) result |= (mask <<= 1)*(attackKey != attacks[x]);
+    return result & ~mask;
+}
+
+int
 NonEvade (StackFrame *f)
 {
     if((f->fromPiece & ~COLOR) != 31) { // moves non-royal (or drops)
@@ -1043,7 +1052,7 @@ Search (int stm, int alpha, int beta, StackFrame *ff, int depth, int reduction,
     int oldSP = moveSP, *pvStart = pvPtr;
     int killer1 = killers[ply][0], killer2 = killers[ply][1], hashMove;
     int bestNr, bestScore, startAlpha, startScore, resultDepth, iterDepth=0, originalReduction = reduction;
-    int hit, hashKeyH, ran=0;
+    int hit, hashKeyH, ran=0, ipMask=0;
     int curEval, score;
 
     // legality
@@ -1108,8 +1117,10 @@ if(hashMove && board[hashMove>>8&255] == 0) {char s[100];sprintf(s,"bad hash mov
 
     // check test
     if(f.checker == CK_UNKNOWN) CheckTest(stm, ff, &f); // test for check if hash did not supply it
-    if(f.checker != CK_NONE) depth++, maxDepth++, reduction =  originalReduction = 0; // extend check evasions
-    else if(depth > 3) {
+    if(f.checker != CK_NONE) {
+       depth++, maxDepth++, reduction = originalReduction = 0 /*, killers[ply][2] = -1*/; // extend check evasions
+       if(earlyGen && f.checkDist && maxDepth <= 1) ipMask = SafeIP(&f);
+    } else if(depth > 3) {
        if(depth - reduction < 3) reduction = depth - 3; // never reduce to below 3 ply
        depth -= reduction;
     } else reduction = originalReduction = 0;
@@ -1138,6 +1149,7 @@ if(PATH)printf("%d:%d   {%d,%d} max=%d eval=%d check=%02x,%d,%d\n",ply,depth,alp
        if(MoveGen(stm, &m, f.rights)) { // impossible (except for hash collision giving wrong in-check status)
            Dump("King capture");
        }
+       if(f.checkDist && maxDepth <= 1) ipMask = SafeIP(&f);
     }
     if(hashMove) moveStack[--m.firstMove] = hashMove; // put hash move in front of list (duplicat!)
     if(f.checker != CK_NONE) moveSP = m.drops = m.castlings; // clip off castlings when in check
@@ -1175,7 +1187,7 @@ if(PATH)printf("%d:%d:%d new iter moveStack[%d..%d]\n",ply,depth,iterDepth,m.fir
                        if(f.checker != CK_NONE) {
                            m.stage |= 4; // when in check we stop after evasion drops
                            if(f.checkDist == 0) continue; // but there cannot be any for contact/double checks
-                           EvasionDrops(stm, &f);
+                           EvasionDrops(stm, &f, ipMask); // at d <= 1 suppress futile interpositions
                            if(moveSP <= curMove) continue; // no avail
                            m.stage = 3; break;
                        }