diff --git a/NineChess/src/config.h b/NineChess/src/config.h index d284f4ee..b4a08894 100644 --- a/NineChess/src/config.h +++ b/NineChess/src/config.h @@ -5,7 +5,9 @@ //#define DEAL_WITH_HORIZON_EFFECT -#define RANDOM_BEST_MOVE +//#define RANDOM_BEST_MOVE + +#define HASH_MAP_ENABLE #ifdef DEBUG #define DONOT_PLAY_SOUND diff --git a/NineChess/src/ninechess.cpp b/NineChess/src/ninechess.cpp index 13c92828..0e47e59c 100644 --- a/NineChess/src/ninechess.cpp +++ b/NineChess/src/ninechess.cpp @@ -1230,7 +1230,7 @@ uint64_t NineChess::chessHash() */ uint64_t hash = 0ull; - for (int i = N_SEATS; i < (N_RINGS + 1) * N_SEATS; i++) { + for (int i = POS_BEGIN; i < POS_END; i++) { hash |= board_[i] & 0x30; hash <<= 2; } diff --git a/NineChess/src/ninechessai_ab.cpp b/NineChess/src/ninechessai_ab.cpp index 4bee0b2c..2e706bf6 100644 --- a/NineChess/src/ninechessai_ab.cpp +++ b/NineChess/src/ninechessai_ab.cpp @@ -14,7 +14,8 @@ NineChessAi_ab::NineChessAi_ab() : rootNode(nullptr), requiredQuit(false), nodeCount(0), - evaluatedNodeCount(0) + evaluatedNodeCount(0), + hashHitCount(0) { buildRoot(); } @@ -82,7 +83,7 @@ struct NineChessAi_ab::Node *NineChessAi_ab::addNode(Node *parent, int value, in } // 静态hashmap初始化 -mutex NineChessAi_ab::mtx; +mutex NineChessAi_ab::hashMapMutex; unordered_map NineChessAi_ab::hashmap; void NineChessAi_ab::buildChildren(Node *node) @@ -231,10 +232,10 @@ void NineChessAi_ab::setChess(const NineChess &chess) { // 如果规则改变,重建hashmap if (strcmp(this->chess_.currentRule.name, chess.currentRule.name)) { - mtx.lock(); + hashMapMutex.lock(); hashmap.clear(); hashmap.reserve(maxHashCount); - mtx.unlock(); + hashMapMutex.unlock(); } this->chess_ = chess; @@ -543,26 +544,33 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node) return node->value; } -#if 0 +#ifdef HASH_MAP_ENABLE // 检索hashmap uint64_t hash = chessTemp.chessHash(); - mtx.lock(); + node->hash = hash; + + hashMapMutex.lock(); + auto iter = findHash(hash); - if (node != rootNode) { - if (iter != hashmap.end()) { - if (iter->second.depth >= depth) { - node->value = iter->second.value; - if (chessContext->turn == NineChess::PLAYER1) - node->value += iter->second.depth - depth; - else - node->value -= iter->second.depth - depth; - mtx.unlock(); - return node->value; - } - } + + if (node != rootNode && + iter != hashmap.end() && + iter->second.depth >= depth) { + node->value = iter->second.value; + + if (chessContext->turn == NineChess::PLAYER1) + node->value += iter->second.depth - depth; + else + node->value -= iter->second.depth - depth; + + hashMapMutex.unlock(); + hashHitCount++; + + return node->value; } - mtx.unlock(); -#endif + + hashMapMutex.unlock(); +#endif /* HASH_MAP_ENABLE */ // 生成子节点树 buildChildren(node); @@ -624,24 +632,24 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node) } #endif -#if 0 - // 添加到hashmap - mtx.lock(); - if (iter == hashmap.end()) { - HashValue hashValue; - hashValue.value = node->value; - hashValue.depth = depth; - if (hashmap.size() <= maxHashCount) - hashmap.insert({hash, hashValue}); +#ifdef HASH_MAP_ENABLE + // 添加到hashmap + hashMapMutex.lock(); + if (iter == hashmap.end()) { + HashValue hashValue; + hashValue.value = node->value; + hashValue.depth = depth; + if (hashmap.size() <= maxHashCount) + hashmap.insert({hash, hashValue}); + } + // 更新更深层数据 + else { + if (iter->second.depth < depth) { + iter->second.value = node->value; + iter->second.depth = depth; } - // 更新更深层数据 - else { - if (iter->second.depth < depth) { - iter->second.value = node->value; - iter->second.depth = depth; - } - } - mtx.unlock(); + } + hashMapMutex.unlock(); #endif // 排序子节点树 @@ -715,6 +723,10 @@ const char* NineChessAi_ab::bestMove() qDebug() << "Return" << retIndex << "of" << bestMovesSize << "results" << "(" << time0 << ")"; #endif +#ifdef HASH_MAP_ENABLE + qDebug() << "Hash hit count:" << hashHitCount; +#endif + return move2string(bestMoves[retIndex]->move); } @@ -749,6 +761,7 @@ unordered_map::iterator NineChessAi_ab::fin for (int i = 0; i < 2; i++) { if (i) chessTempShift.mirror(false); + for (int j = 0; j < 2; j++) { if (j) chessTempShift.turn(false); diff --git a/NineChess/src/ninechessai_ab.h b/NineChess/src/ninechessai_ab.h index 076069b2..ce2a74c7 100644 --- a/NineChess/src/ninechessai_ab.h +++ b/NineChess/src/ninechessai_ab.h @@ -42,6 +42,9 @@ public: struct Node* parent; // 父节点 size_t id; // 结点编号 int rand; // 随机数,对于 value 一致的结点随机排序用 +#ifdef HASH_MAP_ENABLE + uint64_t hash; +#endif #ifdef DEBUG_AB_TREE string cmd; enum NineChess::Player player; // 此招是谁下的 @@ -132,6 +135,9 @@ private: // 评估过的结点个数 size_t evaluatedNodeCount; + // Hash 命中次数 + size_t hashHitCount; + // 局面数据栈 stack contextStack; @@ -139,7 +145,7 @@ private: bool requiredQuit; // 互斥锁 - static mutex mtx; + static mutex hashMapMutex; // 局面数据哈希表 static unordered_map hashmap;