Forbid stand-pat after checking
authorH.G.Muller <hgm@hgm-xboard.(none)>
Sun, 14 May 2017 10:41:21 +0000 (12:41 +0200)
committerH.G.Muller <hgm@hgm-xboard.(none)>
Sun, 14 May 2017 12:38:33 +0000 (14:38 +0200)
If the previous two ply were a check and evasion that burned material,
the stand-pat score is replaced by a (somewhat pessimistic) mated-in-50
score. This prevents pushing forced mates over the horizon by series of
spite checks.

dropper.c

index 50106e3..d590bc2 100644 (file)
--- a/dropper.c
+++ b/dropper.c
@@ -702,7 +702,7 @@ typedef struct {
     Key hashKey, newKey;
     unsigned char fromSqr, toSqr, captSqr, epSqr, rookSqr, rights;
     signed char fromPiece, toPiece, victim, savePiece, rook, mutation;
-    int pstEval, newEval, bulk;
+    int pstEval, newEval, bulk, tpGain;
     int move, wholeMove, depth;
     int checker, checkDir, checkDist, xking;
 } StackFrame;
@@ -1189,9 +1189,11 @@ if(hashMove && board[hashMove>>8&255] == 0) {char s[100];sprintf(s,"bad hash mov
     // stand pat or null move
     startAlpha = alpha; startScore = -INF;
     if(depth <= 0) { // QS
-       if(curEval > alpha) {
-           if(curEval >= beta) { ff->depth = 1; moveSP = oldSP; return curEval; } // stand-pat cutoff
-           alpha = startScore = curEval; maxDepth = 0; // we will not fail low, so no extra iterations
+        int anaEval = curEval;
+       if(ff->checker != CK_NONE && ff->tpGain > 0) anaEval = 50-INF; // forbid stand pat if horizon check tossed material
+       if(anaEval > alpha) {
+           if(anaEval >= beta) { ff->depth = 1; moveSP = oldSP; return anaEval; } // stand-pat cutoff
+           alpha = startScore = anaEval; maxDepth = 0; // we will not fail low, so no extra iterations
        }
        if(maxDepth <= 0) {
            if(board[toDecode[hashMove&255]] == 0) hashMove = 0;
@@ -1312,6 +1314,7 @@ if(PATH)printf("%d:%d:%d new iter moveStack[%d..%d]\n",ply,depth,iterDepth,m.fir
                    int lmr;
                  search:
                    lmr = (curMove >= m.late) + (curMove >= m.drops);
+                   f.tpGain = f.newEval + ff->pstEval;     // material gain in last two ply
                    if(ply==0 && randomize && moveNr < 10) ran = (alpha > INF-100 || alpha <-INF+100 ? 0 : (f.newKey*ranKey>>24 & 31)- 16);
                    repKey[index] = (int)f.newKey & 0x1FFFFF | f.newEval << 21; // remember position
                    // recursion
@@ -1603,7 +1606,7 @@ RootMakeMove(int move)
   int index;
   // irreversibly adopt incrementally updated values from last move as new starting point
   MoveStack m;
-  int checker;
+  int e = undoInfo.pstEval, checker;
   undoInfo.pstEval = -undoInfo.newEval; // (like we initialize new Stackframe in daughter node)
   undoInfo.hashKey = undoInfo.newKey;
   undoInfo.rights |= spoiler[undoInfo.fromSqr] | spoiler[undoInfo.toSqr];
@@ -1613,6 +1616,7 @@ RootMakeMove(int move)
   moveSP = 0; // and throw away those moves
   MakeMove(&undoInfo, move);
   checkHist[moveNr+1] = checker;
+  undoInfo.tpGain = e + undoInfo.newEval;
   // store in game history hash table
   index = (unsigned int)undoInfo.newKey >> 24 ^ stm << 2; // uses high byte of low (= hands-free) key
   while(repKey[index] && (repKey[index] ^ (int)undoInfo.newKey) & 0x1FFFFF) index += 2; // find empty slot