// UCCI支持 - 输出Hash表中的局面信息 bool PopHash(const PositionStruct &pos) { HashStruct hsh; uint32_t dwMoveStr; int i; for (i = 0; i < HASH_LAYERS; i ++) { hsh = HASH_ITEM(pos, i); if (HASH_POS_EQUAL(hsh, pos)) { printf("pophash"); if (hsh.wmv != 0) { __ASSERT(pos.LegalMove(hsh.wmv)); dwMoveStr = MOVE_COORD(hsh.wmv); printf(" bestmove %.4s", (const char *) &dwMoveStr); } if (hsh.ucBetaDepth > 0) { printf(" lowerbound %d depth %d", hsh.svlBeta, hsh.ucBetaDepth); } if (hsh.ucAlphaDepth > 0) { printf(" upperbound %d depth %d", hsh.svlAlpha, hsh.ucAlphaDepth); } printf("\n"); fflush(stdout); return true; } } return false; }
// 检测后续路线是否稳定(不是循环路线),有助于减少置换表的不稳定性 static bool PosStable(const PositionStruct &pos, int mv) { HashStruct hsh; int i, nMoveNum; bool bStable; // pos会沿着路线变化,但最终会还原,所以被视为"const",而让"posMutable"承担非"const"的角色 PositionStruct &posMutable = (PositionStruct &) pos; __ASSERT(mv != 0); nMoveNum = 0; bStable = true; while (!MoveStable(posMutable, mv)) { nMoveNum ++; // "!MoveStable()"表明已经执行了一个着法,以后需要撤消 // 执行这个着法,如果产生循环,那么终止后续路线,并确认该路线不稳定 if (posMutable.RepStatus() > 0) { bStable = false; break; } // 逐层获取置换表项,方法同"ProbeHash()" for (i = 0; i < HASH_LAYERS; i ++) { hsh = HASH_ITEM(posMutable, i); if (HASH_POS_EQUAL(hsh, posMutable)) { break; } } mv = (i == HASH_LAYERS ? 0 : hsh.wmv); } // 撤消前面执行过的所有着法 for (i = 0; i < nMoveNum; i ++) { posMutable.UndoMakeMove(); } return bStable; }
static int pkgname_in_hash(const char *pkgname) { struct pkgname_hash *iter; for (iter = pkgname_hash[HASH_ITEM(pkgname)]; iter != NULL; iter = iter->next) { if (strcmp(iter->pkgname, pkgname) == 0) return 1; } return 0; }
// 获取置换表局面信息(没有命中时,返回"-MATE_VALUE") int ProbeHash(const PositionStruct &pos, int vlAlpha, int vlBeta, int nDepth, bool bNoNull, int &mv) { HashStruct hsh; int i, vl; bool bBanNode, bMateNode; // 获取置换表局面信息的过程包括以下几个步骤: // 1. 逐层获取置换表项 mv = 0; for (i = 0; i < HASH_LAYERS; i ++) { hsh = HASH_ITEM(pos, i); if (HASH_POS_EQUAL(hsh, pos)) { mv = hsh.wmv; __ASSERT(mv == 0 || pos.LegalMove(mv)); break; } } if (i == HASH_LAYERS) { return -MATE_VALUE; } // 2. 判断是否符合Beta边界 if (hsh.ucBetaDepth > 0) { vl = ValueAdjust(pos, bBanNode, bMateNode, hsh.svlBeta); if (!bBanNode && !(hsh.wmv == 0 && bNoNull) && (hsh.ucBetaDepth >= nDepth || bMateNode) && vl >= vlBeta) { __ASSERT_BOUND(1 - MATE_VALUE, vl, MATE_VALUE - 1); if (hsh.wmv == 0 || PosStable(pos, hsh.wmv)) { return vl; } } } // 3. 判断是否符合Alpha边界 if (hsh.ucAlphaDepth > 0) { vl = ValueAdjust(pos, bBanNode, bMateNode, hsh.svlAlpha); if (!bBanNode && (hsh.ucAlphaDepth >= nDepth || bMateNode) && vl <= vlAlpha) { __ASSERT_BOUND(1 - MATE_VALUE, vl, MATE_VALUE - 1); if (hsh.wmv == 0 || PosStable(pos, hsh.wmv)) { return vl; } } } return -MATE_VALUE; }
// 存储置换表局面信息 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; }
static void write_single_job(int fd, const char *begin_entry, struct scan_job *job) { struct pkgname_hash *entry; const char *end_entry, *end_line; char *pkgname; int skip_current; struct iovec output[5]; const int iovcnt = 5; ssize_t expected; for (; begin_entry != NULL && begin_entry[0] != '\0';) { pkgname = pkgname_dup(begin_entry); if (pkgname == NULL) { warnx("pbulk-index output not recognized for %s", job->pkg_location); break; } if (pkgname_in_hash(pkgname)) { warnx("Duplicate package: %s", pkgname); skip_current = 1; } else { skip_current = 0; } end_entry = pbulk_item_end(begin_entry); if (end_entry == NULL) { free(pkgname); warnx("pbulk-index output not recognized for %s", job->pkg_location); break; } if (skip_current == 0) { end_line = strchr(begin_entry, '\n'); if (end_line == NULL || end_line > end_entry) errx(254, "internal error"); output[0].iov_base = UNCONST(begin_entry); expected = output[0].iov_len = end_line + 1 - begin_entry; output[1].iov_base = UNCONST("PKG_LOCATION="); output[1].iov_len = strlen(output[1].iov_base); expected += output[1].iov_len; output[2].iov_base = job->pkg_location; output[2].iov_len = strlen(output[2].iov_base); expected += output[2].iov_len; output[3].iov_base = UNCONST("\n"); output[3].iov_len = 1; expected += output[3].iov_len; output[4].iov_base = UNCONST(end_line + 1); output[4].iov_len = end_entry - end_line - 1; expected += output[4].iov_len; if (writev(fd, output, iovcnt) != expected) err(1, "writev failed"); entry = xmalloc(sizeof(*entry)); entry->next = pkgname_hash[HASH_ITEM(pkgname)]; entry->pkgname = pkgname; pkgname_hash[HASH_ITEM(pkgname)] = entry; } else { free(pkgname); } begin_entry = end_entry; } }