diff --git a/NineChess/Source.cpp b/NineChess/Source.cpp deleted file mode 100644 index e69de29b..00000000 diff --git a/NineChess/src/aithread.cpp b/NineChess/src/aithread.cpp index 7d629568..618ad2e9 100644 --- a/NineChess/src/aithread.cpp +++ b/NineChess/src/aithread.cpp @@ -34,7 +34,9 @@ void AiThread::setAi(const NineChess &chess) this->chess_ = &chess; ai_ab.setChess(*(this->chess_)); +#ifdef HASH_MAP_ENABLE ai_ab.clearHashMap(); +#endif mutex.unlock(); } diff --git a/NineChess/src/config.h b/NineChess/src/config.h index d631cab8..875543f3 100644 --- a/NineChess/src/config.h +++ b/NineChess/src/config.h @@ -1,15 +1,15 @@ #ifndef CONFIG_H #define CONFIG_H -#define DEBUG +//#define DEBUG -//#define RANDOM_MOVE +#define RANDOM_MOVE -//#define DEAL_WITH_HORIZON_EFFECT +#define DEAL_WITH_HORIZON_EFFECT //#define RANDOM_BEST_MOVE -#define HASH_MAP_ENABLE +//#define HASH_MAP_ENABLE //#define DONOT_DELETE_TREE @@ -27,7 +27,7 @@ //#define DONOT_PLAY_SOUND #ifdef DEBUG -#define GAME_PLACING_FIXED_DEPTH 3 +#define GAME_PLACING_FIXED_DEPTH 4 #endif #ifdef DEBUG @@ -48,7 +48,7 @@ #define DRAW_SEAT_NUMBER #endif -//#define IDS_SUPPORT +#define IDS_SUPPORT #define SAVE_CHESSBOOK_WHEN_ACTION_NEW_TRIGGERED diff --git a/NineChess/src/hashmap.cpp b/NineChess/src/hashmap.cpp index 4ecb691d..e4e484c0 100644 --- a/NineChess/src/hashmap.cpp +++ b/NineChess/src/hashmap.cpp @@ -39,7 +39,7 @@ template T& HashMap::at(uint64_t i) { if (i >= capacity) { - qDebug() << "Ë÷Òý³¬¹ý×î´óÖµ"; + qDebug() << "Error"; return pool[0]; } return pool[i]; diff --git a/NineChess/src/hashmap.h b/NineChess/src/hashmap.h index a7160fbb..e511352f 100644 --- a/NineChess/src/hashmap.h +++ b/NineChess/src/hashmap.h @@ -1,4 +1,5 @@ #ifndef HASHMAP_H +#define HASHMAP_H #include #include @@ -8,7 +9,7 @@ class HashMap { public: HashMap(); - HashMap(size_t capacity); + HashMap(size_t capacity); ~HashMap(); enum FindResult @@ -25,6 +26,8 @@ public: return pool[addr]; } + uint64_t hashToAddr(uint64_t hash); + T &find(uint64_t hash) { uint64_t addr = hashToAddr(hash); @@ -39,17 +42,15 @@ public: void insert(uint64_t hash, const T &hashValue); -protected: + bool construct(); + private: size_t capacity; size_t size; - T *pool; + T *pool; - bool construct(); - - uint64_t hashToAddr(uint64_t hash); }; -#endif // HASHMAP_H \ No newline at end of file +#endif // HASHMAP_H diff --git a/NineChess/src/ninechess.cpp b/NineChess/src/ninechess.cpp index 4b88fb99..9e702cfa 100644 --- a/NineChess/src/ninechess.cpp +++ b/NineChess/src/ninechess.cpp @@ -121,11 +121,14 @@ NineChess::NineChess() { // å•ç‹¬æ出 board 等数æ®ï¼Œå…å¾—æ¯æ¬¡éƒ½å†™ context.board; board_ = context.board; + +#ifdef HASH_MAP_ENABLE //hash_ = &context.hash; //zobrist_ = &context.zobrist; // åˆ›å»ºå“ˆå¸Œæ•°æ® constructHash(); +#endif // 默认选择第1å·è§„则,å³â€œæ‰“三棋†setContext(&RULES[1]); @@ -176,6 +179,7 @@ NineChess::~NineChess() { } +#ifdef HASH_MAP_ENABLE void NineChess::constructHash() { context.hash = 0ull; @@ -193,6 +197,7 @@ void NineChess::constructHash() } } } +#endif /* HASH_MAP_ENABLE */ NineChess::Player NineChess::getOpponent(NineChess::Player player) { @@ -324,8 +329,7 @@ void NineChess::createMillTable() // 设置棋局状æ€å’Œæ£‹ç›˜æ•°æ®ï¼Œç”¨äºŽåˆå§‹åŒ– bool NineChess::setContext(const struct Rule *rule, int maxStepsLedToDraw, int maxTimeLedToLose, int initialStep, int flags, const char *board, - int nPiecesInHand_1, int nPiecesInHand_2, int nPiecesNeedRemove, - uint64_t hash, uint64_t hashCheckCode) + int nPiecesInHand_1, int nPiecesInHand_2, int nPiecesNeedRemove) { // 有效性判断 if (maxStepsLedToDraw < 0 || maxTimeLedToLose < 0 || initialStep < 0 || @@ -391,12 +395,16 @@ bool NineChess::setContext(const struct Rule *rule, int maxStepsLedToDraw, int m // 当å‰æ£‹å±€ï¼ˆ3×8) if (board == nullptr) { memset(context.board, 0, sizeof(context.board)); +#ifdef HASH_MAP_ENABLE context.hash = 0ull; context.hashCheckCode = 0ull; +#endif } else { memcpy(context.board, board, sizeof(context.board)); +#ifdef HASH_MAP_ENABLE context.hash = hash; context.hashCheckCode = hashCheckCode; +#endif } // 计算盘é¢å­æ•° @@ -493,8 +501,7 @@ bool NineChess::setContext(const struct Rule *rule, int maxStepsLedToDraw, int m } void NineChess::getContext(struct Rule &rule, int &step, int &flags, - int *&board, int &nPiecesInHand_1, int &nPiecesInHand_2, int &num_NeedRemove, - uint64_t &hash, uint64_t &hashCheckCode) + int *&board, int &nPiecesInHand_1, int &nPiecesInHand_2, int &num_NeedRemove) { rule = this->currentRule; step = this->currentStep; @@ -503,7 +510,9 @@ void NineChess::getContext(struct Rule &rule, int &step, int &flags, nPiecesInHand_1 = context.nPiecesInHand_1; nPiecesInHand_2 = context.nPiecesInHand_2; num_NeedRemove = context.nPiecesNeedRemove; - hashCheckCode = context.hashCheckCode; +#ifdef HASH_MAP_ENABLE + hash = context.hash; +#endif } bool NineChess::reset() @@ -547,9 +556,11 @@ bool NineChess::reset() // 用时置零 elapsedMS_1 = elapsedMS_2 = 0; +#ifdef HASH_MAP_ENABLE // 哈希以åŠå“ˆå¸Œæ ¡éªŒç å½’零 context.hash = 0; context.hashCheckCode = 0; +#endif // æ示 setTips(); @@ -703,7 +714,9 @@ bool NineChess::place(int c, int p, long time_p /* = -1*/) } board_[pos] = piece; +#ifdef HASH_MAP_ENABLE updateHash(pos); +#endif move_ = pos; player_ms = update(time_p); sprintf(cmdline, "(%1u,%1u) %02u:%02u.%03u", @@ -792,9 +805,13 @@ bool NineChess::place(int c, int p, long time_p /* = -1*/) c, p, player_ms / 60000, (player_ms % 60000) / 1000, player_ms % 1000); cmdlist.push_back(string(cmdline)); board_[pos] = board_[currentPos]; +#ifdef HASH_MAP_ENABLE updateHash(pos); +#endif board_[currentPos] = '\x00'; +#ifdef HASH_MAP_ENABLE updateHash(currentPos); +#endif currentPos = pos; currentStep++; n = addMills(currentPos); @@ -880,7 +897,9 @@ bool NineChess::capture(int c, int p, long time_p /* = -1*/) currentPos = 0; context.nPiecesNeedRemove--; currentStep++; +#ifdef HASH_MAP_ENABLE updateHash(pos); +#endif // 去å­å®Œæˆ // 如果决出胜负 @@ -1030,7 +1049,9 @@ bool NineChess::place(int pos) } board_[pos] = piece; +#ifdef HASH_MAP_ENABLE updateHash(pos); +#endif move_ = pos; currentPos = pos; //step++; @@ -1106,9 +1127,13 @@ bool NineChess::place(int pos) // ç§»å­ move_ = (currentPos << 8) + pos; board_[pos] = board_[currentPos]; +#ifdef HASH_MAP_ENABLE updateHash(pos); +#endif board_[currentPos] = '\x00'; +#ifdef HASH_MAP_ENABLE updateHash(currentPos); +#endif currentPos = pos; //step++; n = addMills(currentPos); @@ -1185,7 +1210,9 @@ bool NineChess::capture(int pos) move_ = -pos; currentPos = 0; context.nPiecesNeedRemove--; +#ifdef HASH_MAP_ENABLE updateHash(pos); +#endif //step++; // 去å­å®Œæˆ @@ -1290,6 +1317,8 @@ bool NineChess::choose(int pos) return false; } +#ifdef HASH_MAP_ENABLE + uint64_t NineChess::getHash() { return context.hash; @@ -1341,6 +1370,7 @@ uint64_t NineChess::updateHash(int pos) return context.hashCheckCode; // TODO: 返回什么 } +#endif /* HASH_MAP_ENABLE */ bool NineChess::giveup(Player loser) { @@ -1775,7 +1805,9 @@ void NineChess::cleanForbiddenPoints() pos = i * N_SEATS + j; if (board_[pos] == '\x0f') { board_[pos] = '\x00'; +#ifdef HASH_MAP_ENABLE updateHash(pos); +#endif } } } diff --git a/NineChess/src/ninechess.h b/NineChess/src/ninechess.h index 4a80f26d..bc845e99 100644 --- a/NineChess/src/ninechess.h +++ b/NineChess/src/ninechess.h @@ -179,7 +179,8 @@ public: */ int board[N_POINTS]; - // å±€é¢å“ˆå¸Œçš„校验ç ï¼Œæ ¡éªŒç ç›¸åŒ æ‰èƒ½è®¤ä¸ºæ˜¯åŒä¸€å±€é¢ +#ifdef HASH_MAP_ENABLE + // å±€é¢å“ˆå¸Œçš„校验ç ï¼ˆè¿‡æ—¶ï¼‰ uint64_t hashCheckCode; // å±€é¢çš„哈希值 @@ -189,16 +190,17 @@ public: uint16_t hashAddr; // 标记处于走å­é˜¶æ®µçš„哈希 - uint16_t gameMovingHash; + uint64_t gameMovingHash; // åƒå­åŠ¨ä½œçš„哈希 - uint16_t actionCaptureHash; + uint64_t actionCaptureHash; // 标记轮到玩家2行棋的哈希 - uint16_t player2sTurnHash; + uint64_t player2sTurnHash; // Zobrist 数组 uint64_t zobrist[N_POINTS][POINT_TYPE_COUNT]; +#endif /* HASH_MAP_ENABLE */ // å±€é¢é˜¶æ®µæ ‡è¯† enum NineChess::GameStage stage; @@ -283,15 +285,12 @@ public: const char *board = nullptr, // 默认空棋盘 int nPiecesInHand_1 = 12, // 玩家1剩余未放置å­æ•° int nPiecesInHand_2 = 12, // 玩家2剩余未放置å­æ•° - int nPiecesNeedRemove = 0, // 尚待去除的å­æ•° - uint64_t hash = 0ull, // 哈希值 - uint64_t hashCheckCode = 0ull // å“ˆå¸Œæ ¡éªŒç  + int nPiecesNeedRemove = 0 // 尚待去除的å­æ•° ); // 获å–棋局状æ€å’Œæ£‹ç›˜ä¸Šä¸‹æ–‡ void getContext(struct Rule &rule, int &step, int &flags, int *&board, - int &nPiecesInHand_1, int &p2_nPiecesInHand_2InHand, int &nPiecesNeedRemove, - uint64_t &hash, uint64_t &hashCheckCode); + int &nPiecesInHand_1, int &p2_nPiecesInHand_2InHand, int &nPiecesNeedRemove); // 获å–当å‰è§„则 const struct Rule *getRule() const @@ -495,10 +494,12 @@ protected: bool place(int pos); bool capture(int pos); +#ifdef HASH_MAP_ENABLE // hash相关 uint64_t getHash(); uint64_t getHashCheckCode(); uint64_t updateHash(int pos); +#endif /* HASH_MAP_ENABLE */ private: // 当å‰ä½¿ç”¨çš„规则 diff --git a/NineChess/src/ninechessai_ab.cpp b/NineChess/src/ninechessai_ab.cpp index 4d4913dc..2a67ea26 100644 --- a/NineChess/src/ninechessai_ab.cpp +++ b/NineChess/src/ninechessai_ab.cpp @@ -22,6 +22,10 @@ NineChessAi_ab::NineChessAi_ab() : hashHitCount(0) { buildRoot(); + +#ifdef HASH_MAP_ENABLE + hashMap.construct(); // TODO +#endif } NineChessAi_ab::~NineChessAi_ab() @@ -61,7 +65,9 @@ struct NineChessAi_ab::Node *NineChessAi_ab::addNode(Node *parent, int value, in newNode->alpha = -INF_VALUE; newNode->beta = INF_VALUE; newNode->result = 0; +#ifdef HASH_MAP_ENABLE newNode->isHash = false; +#endif newNode->visited = false; int c, p; @@ -94,8 +100,7 @@ struct NineChessAi_ab::Node *NineChessAi_ab::addNode(Node *parent, int value, in //mutex NineChessAi_ab::hashMapMutex; //HashMap NineChessAi_ab::hashmap; -mutex hashMapMutex; -HashMap hashmap; + #ifdef MOVE_PRIORITY_TABLE_SUPPORT #ifdef RANDOM_MOVE @@ -359,10 +364,12 @@ void NineChessAi_ab::deleteTree(Node *node) void NineChessAi_ab::setChess(const NineChess &chess) { +#ifdef HASH_MAP_ENABLE // 如果规则改å˜ï¼Œé‡å»ºhashmap if (strcmp(this->chess_.currentRule.name, chess.currentRule.name)) { clearHashMap(); } +#endif this->chess_ = chess; chessTemp = chess; @@ -602,8 +609,10 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node) // 临时增加的深度,克æœæ°´å¹³çº¿æ•ˆåº”用 int epsilon = 0; +#ifdef HASH_MAP_ENABLE // 哈希类型 enum HashType hashf = hashfALPHA; +#endif #ifdef DEBUG_AB_TREE node->depth = depth; @@ -612,10 +621,12 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node) // åˆå§‹åŒ– node->isLeaf = false; node->isTimeout = false; - node->isHash = false; node->visited = true; +#ifdef HASH_MAP_ENABLE + node->isHash = false; node->hash = 0; -#endif +#endif // HASH_MAP_ENABLE +#endif // DEBUG_AB_TREE #ifdef HASH_MAP_ENABLE // 检索 hashmap @@ -758,8 +769,9 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node) // α 为走棋一方æœç´¢åˆ°çš„最好值,任何比它å°çš„值对当å‰ç»“点的走棋方都没有æ„义 // 如果æŸä¸ªç€æ³•çš„结果å°äºŽæˆ–等于 α,那么它就是很差的ç€æ³•ï¼Œå› æ­¤å¯ä»¥æŠ›å¼ƒ alpha = std::max(value, alpha); - +#ifdef HASH_MAP_ENABLE hashf = hashfALPHA; // ???? +#endif } else { @@ -776,8 +788,9 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node) // 如果æŸä¸ªç€æ³•çš„结果大于或等于 β,那么整个结点就作废了,因为对手ä¸å¸Œæœ›èµ°åˆ°è¿™ä¸ªå±€é¢ï¼Œè€Œå®ƒæœ‰åˆ«çš„ç€æ³•å¯ä»¥é¿å…到达这个局é¢ã€‚ // 因此如果我们找到的评价大于或等于β,就è¯æ˜Žäº†è¿™ä¸ªç»“点是ä¸ä¼šå‘生的,因此剩下的åˆç†ç€æ³•æ²¡æœ‰å¿…è¦å†æœç´¢ã€‚ beta = std::min(value, beta); - +#ifdef HASH_MAP_ENABLE hashf = hashfBETA; // ???? +#endif } // 如果æŸä¸ªç€æ³•çš„结果大于 α 但å°äºŽÎ²ï¼Œé‚£ä¹ˆè¿™ä¸ªç€æ³•å°±æ˜¯èµ°æ£‹ä¸€æ–¹å¯ä»¥è€ƒè™‘èµ°çš„ @@ -834,16 +847,18 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node) return node->value; } +#ifdef HASH_MAP_ENABLE int NineChessAi_ab::recordHash(const HashValue &hashValue) { #ifdef HASH_MAP_ENABLE hashMapMutex.lock(); - hashmap.insert(hashValue.hash, hashValue); + hashMap.insert(hashValue.hash, hashValue); hashMapMutex.unlock(); #endif // HASH_MAP_ENABLE return 0; } +#endif const char* NineChessAi_ab::bestMove() { @@ -940,9 +955,10 @@ const char *NineChessAi_ab::move2string(int move) return cmdline; } +#ifdef HASH_MAP_ENABLE NineChessAi_ab::HashValue NineChessAi_ab::findHash(uint64_t hash) { - NineChessAi_ab::HashValue hashValue = hashmap.find(hash); + NineChessAi_ab::HashValue hashValue = hashMap.find(hash); // TODO: å˜æ¢å±€é¢ #if 0 @@ -974,6 +990,7 @@ NineChessAi_ab::HashValue NineChessAi_ab::findHash(uint64_t hash) void NineChessAi_ab::clearHashMap() { hashMapMutex.lock(); - hashmap.clear(); + hashMap.clear(); hashMapMutex.unlock(); } +#endif /* HASH_MAP_ENABLE */ \ No newline at end of file diff --git a/NineChess/src/ninechessai_ab.h b/NineChess/src/ninechessai_ab.h index caae4c08..5dd6a7c5 100644 --- a/NineChess/src/ninechessai_ab.h +++ b/NineChess/src/ninechessai_ab.h @@ -27,6 +27,7 @@ using namespace std; class NineChessAi_ab { public: +#ifdef HASH_MAP_ENABLE // 定义哈希值的类型 enum HashType : int16_t { @@ -46,6 +47,7 @@ public: uint64_t hash; enum HashType type; }; +#endif /* HASH_MAP_ENABLE */ // 定义一个节点结构体 struct Node @@ -57,9 +59,11 @@ public: struct Node* parent; // 父节点 size_t id; // ç»“ç‚¹ç¼–å· int rand; // éšæœºæ•°ï¼Œå¯¹äºŽ value 一致的结点éšæœºæŽ’åºç”¨ +#ifdef HASH_MAP_ENABLE uint64_t hash; uint64_t hashCheckCode; bool isHash; // 是å¦ä»Ž Hash è¯»å– +#endif /* HASH_MAP_ENABLE */ bool pruned; // 是å¦åœ¨æ­¤å¤„å‰ªæž #ifdef DEBUG_AB_TREE string cmd; @@ -116,13 +120,20 @@ public: // 返回最佳走法的命令行 const char *bestMove(); +#ifdef HASH_MAP_ENABLE // 清空哈希表 void clearHashMap(); +#endif // 比较函数 static bool nodeLess(const Node *first, const Node *second); static bool nodeGreater(const Node *first, const Node *second); +#ifdef HASH_MAP_ENABLE + static std::mutex hashMapMutex; + static HashMap hashMap; +#endif + protected: // 生æˆæ‰€æœ‰åˆæ³•çš„ç€æ³•å¹¶å»ºç«‹å­èŠ‚点 void generateLegalMoves(Node *node); @@ -139,8 +150,10 @@ protected: // 增加新节点 struct Node *addNode(Node *parent, int value, NineChess::move_t move, enum NineChess::Player player); +#ifdef HASH_MAP_ENABLE // æ’入哈希表 int recordHash(const HashValue &hashValue); +#endif // 评价函数 int evaluate(Node *node); @@ -161,8 +174,10 @@ protected: #endif #endif +#ifdef HASH_MAP_ENABLE // 查找哈希表 HashValue findHash(uint64_t hash); +#endif private: // 原始模型 @@ -212,7 +227,4 @@ private: char cmdline[32]; }; -extern mutex hashMapMutex; -extern HashMap hashmap; - #endif