/* 判断获取置换表要符合哪些条件,置换表的分值针对四个不同的区间有不同的处理: * 一、如果分值在"WIN_VALUE"以内(即介于"-WIN_VALUE"到"WIN_VALUE"之间,下同),则只获取满足搜索深度要求的局面; * 二、如果分值在"WIN_VALUE"和"BAN_VALUE"之间,则不能获取置换表中的值(只能获取最佳着法仅供参考),目的是防止由于长将而导致的“置换表的不稳定性”; * 三、如果分值在"BAN_VALUE"以外,则获取局面时不必考虑搜索深度要求,因为这些局面已经被证明是杀棋了; * 四、如果分值是"DrawValue()"(是第一种情况的特殊情况),则不能获取置换表中的值(原因与第二种情况相同)。 * 注意:对于第三种情况,要对杀棋步数进行调整! */ inline int ValueAdjust(const PositionStruct &pos, bool &bBanNode, bool &bMateNode, int vl) { bBanNode = bMateNode = false; if (vl > WIN_VALUE) { if (vl <= BAN_VALUE) { bBanNode = true; } else { bMateNode = true; vl -= pos.nDistance; } } else if (vl < -WIN_VALUE) { if (vl >= -BAN_VALUE) { bBanNode = true; } else { bMateNode = true; vl += pos.nDistance; } } else if (vl == pos.DrawValue()) { bBanNode = true; } return vl; }
// 存储置换表局面信息 void RecordHash(const PositionStruct &pos, int nFlag, int vl, int nDepth, int mv) { HashStruct hsh; int i, nHashDepth, nMinDepth, nMinLayer; // 存储置换表局面信息的过程包括以下几个步骤: // 1. 对分值做杀棋步数调整; __ASSERT_BOUND(1 - MATE_VALUE, vl, MATE_VALUE - 1); __ASSERT(mv == 0 || pos.LegalMove(mv)); if (vl > WIN_VALUE) { if (mv == 0 && vl <= BAN_VALUE) { return; // 导致长将的局面(不进行置换裁剪)如果连最佳着法也没有,那么没有必要写入置换表 } vl += pos.nDistance; } else if (vl < -WIN_VALUE) { if (mv == 0 && vl >= -BAN_VALUE) { return; // 同理 } vl -= pos.nDistance; } else if (vl == pos.DrawValue() && mv == 0) { return; // 同理 } // 2. 逐层试探置换表; nMinDepth = 512; nMinLayer = 0; for (i = 0; i < HASH_LAYERS; i ++) { hsh = HASH_ITEM(pos, i); // 3. 如果试探到一样的局面,那么更新置换表信息即可; if (HASH_POS_EQUAL(hsh, pos)) { // 如果深度更深,或者边界缩小,都可更新置换表的值 if ((nFlag & HASH_ALPHA) != 0 && (hsh.ucAlphaDepth <= nDepth || hsh.svlAlpha >= vl)) { hsh.ucAlphaDepth = nDepth; hsh.svlAlpha = vl; } // Beta结点要注意:不要用Null-Move的结点覆盖正常的结点 if ((nFlag & HASH_BETA) != 0 && (hsh.ucBetaDepth <= nDepth || hsh.svlBeta <= vl) && (mv != 0 || hsh.wmv == 0)) { hsh.ucBetaDepth = nDepth; hsh.svlBeta = vl; } // 最佳着法是始终覆盖的 if (mv != 0) { hsh.wmv = mv; } HASH_ITEM(pos, i) = hsh; return; } // 4. 如果不是一样的局面,那么获得深度最小的置换表项; nHashDepth = MAX((hsh.ucAlphaDepth == 0 ? 0 : hsh.ucAlphaDepth + 256), (hsh.wmv == 0 ? hsh.ucBetaDepth : hsh.ucBetaDepth + 256)); __ASSERT(nHashDepth < 512); if (nHashDepth < nMinDepth) { nMinDepth = nHashDepth; nMinLayer = i; } } // 5. 记录置换表。 hsh.dwZobristLock0 = pos.zobr.dwLock0; hsh.dwZobristLock1 = pos.zobr.dwLock1; hsh.wmv = mv; hsh.ucAlphaDepth = hsh.ucBetaDepth = 0; hsh.svlAlpha = hsh.svlBeta = 0; if ((nFlag & HASH_ALPHA) != 0) { hsh.ucAlphaDepth = nDepth; hsh.svlAlpha = vl; } if ((nFlag & HASH_BETA) != 0) { hsh.ucBetaDepth = nDepth; hsh.svlBeta = vl; } HASH_ITEM(pos, nMinLayer) = hsh; }
// 调整型局面评价函数 inline int Evaluate(const PositionStruct &pos, int vlAlpha, int vlBeta) { int vl; vl = Search.bKnowledge ? pos.Evaluate(vlAlpha, vlBeta) : pos.Material(); return vl == pos.DrawValue() ? vl - 1 : vl; }