diff --git a/include/config.h b/include/config.h index f2a6e719..59ecefeb 100644 --- a/include/config.h +++ b/include/config.h @@ -88,6 +88,7 @@ #define CLEAR_TRANSPOSITION_TABLE #define TRANSPOSITION_TABLE_FAKE_CLEAN #define TRANSPOSITION_TABLE_CUTDOWN +//#define BEST_MOVE_ENABLE //#define TRANSPOSITION_TABLE_DEBUG #endif diff --git a/src/ai/movegen.cpp b/src/ai/movegen.cpp index a56b481f..cad00a75 100644 --- a/src/ai/movegen.cpp +++ b/src/ai/movegen.cpp @@ -24,8 +24,14 @@ #include "misc.h" #include "option.h" -void MoveList::generate(AIAlgorithm &ai, Game &tempGame, - Node *parent, Node *root, move_t bestMove) +void MoveList::generate(AIAlgorithm &ai, + Game &tempGame, + Node *parent, + Node *root +#ifdef BEST_MOVE_ENABLE + , move_t bestMove +#endif // BEST_MOVE_ENABLE + ) { square_t square = SQ_0; player_t opponent = PLAYER_NOBODY; @@ -47,11 +53,19 @@ void MoveList::generate(AIAlgorithm &ai, Game &tempGame, // 否则如果是空位 if (tempGame.position.phase != PHASE_READY || parent != root) { - ai.addNode(parent, VALUE_ZERO, RATING_ZERO, (move_t)square, bestMove); + ai.addNode(parent, VALUE_ZERO, RATING_ZERO, (move_t)square +#ifdef BEST_MOVE_ENABLE + , bestMove +#endif // BEST_MOVE_ENABLE + ); } else { // 若为先手,则抢占星位 if (Board::isStar(square)) { - ai.addNode(parent, VALUE_INFINITE, RATING_STAR_SQUARE, (move_t)square, bestMove); + ai.addNode(parent, VALUE_INFINITE, RATING_STAR_SQUARE, (move_t)square +#ifdef BEST_MOVE_ENABLE + , bestMove +#endif // BEST_MOVE_ENABLE + ); } } } @@ -78,7 +92,11 @@ void MoveList::generate(AIAlgorithm &ai, Game &tempGame, newSquare = static_cast(moveTable[oldSquare][direction]); if (newSquare && !tempGame.boardLocations[newSquare]) { move_t move = move_t((oldSquare << 8) + newSquare); - ai.addNode(parent, VALUE_ZERO, RATING_ZERO, move, bestMove); // (12%) + ai.addNode(parent, VALUE_ZERO, RATING_ZERO, move +#ifdef BEST_MOVE_ENABLE + , bestMove +#endif // BEST_MOVE_ENABLE + ); } } } else { @@ -86,7 +104,11 @@ void MoveList::generate(AIAlgorithm &ai, Game &tempGame, for (newSquare = SQ_BEGIN; newSquare < SQ_END; newSquare = static_cast(newSquare + 1)) { if (!tempGame.boardLocations[newSquare]) { move_t move = move_t((oldSquare << 8) + newSquare); - ai.addNode(parent, VALUE_ZERO, RATING_ZERO, move, bestMove); + ai.addNode(parent, VALUE_ZERO, RATING_ZERO, move +#ifdef BEST_MOVE_ENABLE + , bestMove +#endif // BEST_MOVE_ENABLE + ); } } } @@ -103,7 +125,11 @@ void MoveList::generate(AIAlgorithm &ai, Game &tempGame, for (int i = Board::MOVE_PRIORITY_TABLE_SIZE - 1; i >= 0; i--) { square = static_cast(movePriorityTable[i]); if (tempGame.boardLocations[square] & opponent) { - ai.addNode(parent, VALUE_ZERO, RATING_ZERO, (move_t)-square, bestMove); + ai.addNode(parent, VALUE_ZERO, RATING_ZERO, (move_t)-square +#ifdef BEST_MOVE_ENABLE + , bestMove +#endif // BEST_MOVE_ENABLE + ); } } break; @@ -114,7 +140,11 @@ void MoveList::generate(AIAlgorithm &ai, Game &tempGame, square = static_cast(movePriorityTable[i]); if (tempGame.boardLocations[square] & opponent) { if (rule.allowRemoveMill || !tempGame.position.board.inHowManyMills(square)) { - ai.addNode(parent, VALUE_ZERO, RATING_ZERO, (move_t)-square, bestMove); + ai.addNode(parent, VALUE_ZERO, RATING_ZERO, (move_t)-square +#ifdef BEST_MOVE_ENABLE + , bestMove +#endif // BEST_MOVE_ENABLE + ); } } } diff --git a/src/ai/movegen.h b/src/ai/movegen.h index d153bff3..0e862e35 100644 --- a/src/ai/movegen.h +++ b/src/ai/movegen.h @@ -32,9 +32,14 @@ public: MoveList &operator=(const MoveList &) = delete; // 生成所有合法的着法并建立子节点 - static void generate(AIAlgorithm &ai, Game &tempGame, - Node *parent, Node *root, - move_t bestMove); + static void generate(AIAlgorithm &ai, + Game &tempGame, + Node *parent, + Node *root +#ifdef BEST_MOVE_ENABLE + , move_t bestMove +#endif // BEST_MOVE_ENABLE + ); // 生成着法表 static void create(); diff --git a/src/ai/search.cpp b/src/ai/search.cpp index 6cffc6dc..1bf69f26 100644 --- a/src/ai/search.cpp +++ b/src/ai/search.cpp @@ -167,7 +167,11 @@ depth_t AIAlgorithm::changeDepth(depth_t origDepth) void AIAlgorithm::buildRoot() { - root = addNode(nullptr, VALUE_ZERO, RATING_ZERO, MOVE_NONE, MOVE_NONE); + root = addNode(nullptr, VALUE_ZERO, RATING_ZERO, MOVE_NONE +#ifdef BEST_MOVE_ENABLE + , MOVE_NONE +#endif // BEST_MOVE_ENABLE + ); root->sideToMove = PLAYER_NOBODY; assert(root != nullptr); @@ -177,8 +181,10 @@ Node *AIAlgorithm::addNode( Node *parent, const value_t &value, const rating_t &rating, - const move_t &move, - const move_t &bestMove + const move_t &move +#ifdef BEST_MOVE_ENABLE + , const move_t &bestMove +#endif // BEST_MOVE_ENABLE ) { Node *newNode = (Node *)memmgr.memmgr_alloc(sizeof(Node)); @@ -253,13 +259,13 @@ Node *AIAlgorithm::addNode( parent->children[parent->childrenSize] = newNode; parent->childrenSize++; -#if 0 +#ifdef BEST_MOVE_ENABLE // 如果启用了置换表并且不是叶子结点 if (move == bestMove && move != 0) { newNode->rating += RATING_TT; return newNode; } -#endif +#endif // BEST_MOVE_ENABLE // 若没有启用置换表,或启用了但为叶子节点,则 bestMove 为0 square_t sq = SQ_0; @@ -660,8 +666,10 @@ value_t AIAlgorithm::search(depth_t depth, value_t alpha, value_t beta, Node *no // 临时增加的深度,克服水平线效应用 depth_t epsilon = 0; +#ifdef BEST_MOVE_ENABLE // 子节点的最优着法 move_t bestMove = MOVE_NONE; +#endif // BEST_MOVE_ENABLE #if defined (TRANSPOSITION_TABLE_ENABLE) || defined(ENDGAME_LEARNING) // 获取哈希值 @@ -701,7 +709,11 @@ value_t AIAlgorithm::search(depth_t depth, value_t alpha, value_t beta, Node *no TT::HashType type = TT::hashfEMPTY; - value_t probeVal = TT::probeHash(hash, depth, alpha, beta, bestMove, type); + value_t probeVal = TT::probeHash(hash, depth, alpha, beta, type +#ifdef BEST_MOVE_ENABLE + , bestMove +#endif // BEST_MOVE_ENABLE + ); if (probeVal != VALUE_UNKNOWN) { #ifdef DEBUG_MODE @@ -779,14 +791,25 @@ value_t AIAlgorithm::search(depth_t depth, value_t alpha, value_t beta, Node *no #ifdef TRANSPOSITION_TABLE_ENABLE // 记录确切的哈希值 - TT::recordHash(node->value, depth, TT::hashfEXACT, hash, MOVE_NONE); + TT::recordHash(node->value, + depth, + TT::hashfEXACT, + hash +#ifdef BEST_MOVE_ENABLE + , MOVE_NONE +#endif // BEST_MOVE_ENABLE + ); #endif return node->value; } // 生成子节点树,即生成每个合理的着法 - MoveList::generate(*this, tempGame, node, root, bestMove); + MoveList::generate(*this, tempGame, node, root +#ifdef BEST_MOVE_ENABLE + , bestMove +#endif // BEST_MOVE_ENABLE + ); // 排序子节点树 sortMoves(node); @@ -926,7 +949,14 @@ value_t AIAlgorithm::search(depth_t depth, value_t alpha, value_t beta, Node *no #ifdef TRANSPOSITION_TABLE_ENABLE // 记录不一定确切的哈希值 - TT::recordHash(node->value, depth, hashf, hash, node->children[0]->move); + TT::recordHash(node->value, + depth, + hashf, + hash +#ifdef BEST_MOVE_ENABLE + , node->children[0]->move +#endif // BEST_MOVE_ENABLE + ); #endif /* TRANSPOSITION_TABLE_ENABLE */ // 返回 diff --git a/src/ai/search.h b/src/ai/search.h index db615252..dbb13d18 100644 --- a/src/ai/search.h +++ b/src/ai/search.h @@ -162,8 +162,14 @@ public: public: /* TODO: Move to private or protected */ // 增加新节点 - Node *addNode(Node *parent, const value_t &value, const rating_t &rating, - const move_t &move, const move_t &bestMove); + Node *addNode(Node *parent, + const value_t &value, + const rating_t &rating, + const move_t &move +#ifdef BEST_MOVE_ENABLE + , const move_t &bestMove +#endif // BEST_MOVE_ENABLE + ); protected: // 对合法的着法降序排序 diff --git a/src/ai/tt.cpp b/src/ai/tt.cpp index 2cc0e73e..0b70df0a 100644 --- a/src/ai/tt.cpp +++ b/src/ai/tt.cpp @@ -31,7 +31,11 @@ value_t TT::probeHash(const hash_t &hash, const depth_t &depth, const value_t &alpha, const value_t &beta, - move_t &bestMove, HashType &type) + HashType &type +#ifdef BEST_MOVE_ENABLE + , move_t &bestMove +#endif // BEST_MOVE_ENABLE + ) { HashValue hashValue{}; @@ -69,7 +73,11 @@ value_t TT::probeHash(const hash_t &hash, } out: + +#ifdef BEST_MOVE_ENABLE bestMove = hashValue.bestMove; +#endif // BEST_MOVE_ENABLE + return VALUE_UNKNOWN; } @@ -105,8 +113,11 @@ bool TT::findHash(const hash_t &hash, TT::HashValue &hashValue) int TT::recordHash(const value_t &value, const depth_t &depth, const TT::HashType &type, - const hash_t &hash, - const move_t &bestMove) + const hash_t &hash +#ifdef BEST_MOVE_ENABLE + , const move_t &bestMove +#endif // BEST_MOVE_ENABLE + ) { // 同样深度或更深时替换 // 注意: 每走一步以前都必须把散列表中所有的标志项置为 hashfEMPTY @@ -130,7 +141,10 @@ int TT::recordHash(const value_t &value, hashValue.value = value; hashValue.depth = depth; hashValue.type = type; + +#ifdef BEST_MOVE_ENABLE hashValue.bestMove = bestMove; +#endif // BEST_MOVE_ENABLE #ifdef TRANSPOSITION_TABLE_FAKE_CLEAN hashValue.age = transpositionTableAge; diff --git a/src/ai/tt.h b/src/ai/tt.h index 28f59025..405f0e01 100644 --- a/src/ai/tt.h +++ b/src/ai/tt.h @@ -53,15 +53,32 @@ public: #ifdef TRANSPOSITION_TABLE_FAKE_CLEAN uint8_t age; #endif // TRANSPOSITION_TABLE_FAKE_CLEAN +#ifdef BEST_MOVE_ENABLE move_t bestMove; +#endif // BEST_MOVE_ENABLE }; // 查找哈希表 static bool findHash(const hash_t &hash, HashValue &hashValue); - static value_t probeHash(const hash_t &hash, const depth_t &depth, const value_t &alpha, const value_t &beta, move_t &bestMove, HashType &type); + static value_t probeHash(const hash_t &hash, + const depth_t &depth, + const value_t &alpha, + const value_t &beta, + HashType &type +#ifdef BEST_MOVE_ENABLE + , move_t &bestMove +#endif // BEST_MOVE_ENABLE + ); // 插入哈希表 - static int recordHash(const value_t &value, const depth_t &depth, const HashType &type, const hash_t &hash, const move_t &bestMove); + static int recordHash(const value_t &value, + const depth_t &depth, + const HashType &type, + const hash_t &hash +#ifdef BEST_MOVE_ENABLE + , const move_t &bestMove +#endif // BEST_MOVE_ENABLE + ); // 清空置换表 static void clear();