Remember 12 bits of eval in repeat keys
authorH.G.Muller <hgm@hgm-xboard.(none)>
Sat, 17 Feb 2018 13:23:29 +0000 (14:23 +0100)
committerH.G.Muller <hgm@hgm-xboard.(none)>
Sat, 17 Feb 2018 13:39:59 +0000 (14:39 +0100)
The repeat key is a combination of the hash key for the board position,
and the evaluation. This is used for detecting pseudo-repeats, where the
eval part is then used to forbid material-buring loops. But burning a
Queen changes the eval by 2*600 = 1200 points, and 12 bits are needed
to store that without (signed!) overflow. As only 11 bits were used,
loops burning a Queen were considered winning. This would still be the
case for loops burning two Queens.
  Increasing the number of eval bits to 12 has increased the probability
for a falsely detected pseudo-repetition to one in a million, which still
seems acceptable.

dropper.c

index 34e11f8..959a50a 100644 (file)
--- a/dropper.c
+++ b/dropper.c
@@ -574,7 +574,7 @@ printf("# variant %d: %s\n", v, variants[v].name);
     for(i=0; *ip >= 0; i++) pieceValues[WHITE+i] = pieceValues[BLACK+i] = *ip++;       // basic
     for(i=16,ip++; *ip >= 0; i++) pieceValues[WHITE+i] = pieceValues[BLACK+i] = *ip++; // promoted
     for(i=0, ip++; *ip >= 0; i++) handVal[WHITE+i] = handVal[BLACK+i] = *ip++;         // in hand
-    pawn = 2*handVal[WHITE] << 21; // used for detection of material-loosing loops
+    pawn = 2*handVal[WHITE] << 20; // used for detection of material-loosing loops
     for(i=0; i<16; i++) {
        int demoted = dropType[handSlot[WHITE+i+16]]-1; // piece type after demotion (could be Pawn, in Chess)
        handVal[WHITE+i+16] = handVal[BLACK+i+16] = pieceValues[WHITE+i+16] + handVal[demoted];   // gain by capturing promoted piece
@@ -1331,10 +1331,10 @@ Search (int stm, int alpha, int beta, StackFrame *ff, int depth, int reduction,
 
                // repetition checking
                int index = (unsigned int)f.newKey >> 24 ^ stm << 2; // uses high byte of low (= hands-free) key
-               while(repKey[index] && (repKey[index] ^ (int)f.newKey) & 0x1FFFFF) index++;
+               while(repKey[index] && (repKey[index] ^ (int)f.newKey) & 0xFFFFF) index++;
                int oldRepKey = repKey[index], oldRepDep = repDep[index];
                if(oldRepKey && ff->mutation != -2) { // key present in table: (quasi-)repetition
-                   int gain = (f.newEval << 21) - (repKey[index] & 0xFFE00000);
+                   int gain = (f.newEval << 20) - (repKey[index] & 0xFFF00000);
                    if(gain == 0) { // true repeat
                        score = 0;
                        if(perpLoses) { // repetitions not always draw
@@ -1350,8 +1350,8 @@ Search (int stm, int alpha, int beta, StackFrame *ff, int depth, int reduction,
                           
                        }
                    }
-                   else if(gain == pawn  || gain >= (400<<21)) score = INF-1;  // quasi-repeat with extra piece in hand
-                   else if(gain == -pawn || gain <= (-400<<21)) score = 1-INF; // or with one piece less
+                   else if(gain == pawn  || gain >= (400<<20)) score = INF-1;  // quasi-repeat with extra piece in hand
+                   else if(gain == -pawn || gain <= (-400<<20)) score = 1-INF; // or with one piece less
                    else goto search;// traded one hand piece for another; could still lead somewhere
                    f.lim = score; f.depth = (score >= beta ? highDepth+1 : iterDepth); // minimum required depth
                    *pvPtr = 0; // fake that daughter returned empty PV
@@ -1361,7 +1361,7 @@ Search (int stm, int alpha, int beta, StackFrame *ff, int depth, int reduction,
                    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; repDep[index] = ply + moveNr; // remember position
+                   repKey[index] = (int)f.newKey & 0xFFFFF | f.newEval << 20; repDep[index] = ply + moveNr; // remember position
                    // recursion
                    deprec[ply] = (f.checker != CK_NONE ? f.checker : 0)<<24 | maxDepth<<16 | depth<< 8 | iterDepth; path[ply++] = moveStack[curMove] & 0xFFFF;
                    score = -Search(stm, -beta, -alpha+ran, &f, iterDepth-1, lmr, highDepth);
@@ -1689,8 +1689,8 @@ RootMakeMove(int move)
   if(moveNr >= 19 && !perpLoses) PST[WHITE+1] = knightPST, PST[BLACK+1] = knightPST + 11;
   // 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++; // find empty slot
-  repKey[index] = (int)undoInfo.newKey & 0x1FFFFF | undoInfo.newEval << 21; // remember position
+  while(repKey[index] && (repKey[index] ^ (int)undoInfo.newKey) & 0xFFFFF) index++; // find empty slot
+  repKey[index] = (int)undoInfo.newKey & 0xFFFFF | undoInfo.newEval << 20; // remember position
   repDep[index] = moveNr;
   stm ^= COLOR; moveNr++;
   return 1;