commit
5aff5d8d29
|
@ -11,6 +11,8 @@
|
|||
|
||||
#define HASH_MAP_ENABLE
|
||||
|
||||
//#define BOOK_LEARNING
|
||||
|
||||
//#define DONOT_DELETE_TREE
|
||||
|
||||
#define MOVE_PRIORITY_TABLE_SUPPORT
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include "ninechess.h"
|
||||
#include "ninechessai_ab.h"
|
||||
|
||||
// 对静态常量数组的定义要放在类外,不要放在头文件
|
||||
// 预定义的4套规则
|
||||
|
@ -122,7 +123,7 @@ NineChess::NineChess()
|
|||
// 单独提出 board 等数据,免得每次都写 context.board;
|
||||
board_ = context.board;
|
||||
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
//hash_ = &context.hash;
|
||||
//zobrist_ = &context.zobrist;
|
||||
|
||||
|
@ -375,14 +376,13 @@ 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
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
context.hash = 0ull;
|
||||
#endif
|
||||
} else {
|
||||
memcpy(context.board, board, sizeof(context.board));
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
//context.hash = hash;
|
||||
//context.hashCheckCode = hashCheckCode;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -489,7 +489,7 @@ void NineChess::getContext(struct Rule &rule, int &step, int &flags,
|
|||
nPiecesInHand_1 = context.nPiecesInHand_1;
|
||||
nPiecesInHand_2 = context.nPiecesInHand_2;
|
||||
num_NeedRemove = context.nPiecesNeedRemove;
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
//hash = context.hash;
|
||||
#endif
|
||||
}
|
||||
|
@ -535,7 +535,7 @@ bool NineChess::reset()
|
|||
// 用时置零
|
||||
elapsedMS_1 = elapsedMS_2 = 0;
|
||||
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
// 哈希归零
|
||||
context.hash = 0;
|
||||
#endif
|
||||
|
@ -693,7 +693,7 @@ bool NineChess::place(int c, int p, long time_p /* = -1*/)
|
|||
|
||||
board_[pos] = piece;
|
||||
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
updateHash(pos);
|
||||
#endif
|
||||
move_ = pos;
|
||||
|
@ -784,11 +784,11 @@ 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
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
updateHash(pos);
|
||||
#endif
|
||||
board_[currentPos] = '\x00';
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
revertHash(currentPos);
|
||||
#endif
|
||||
currentPos = pos;
|
||||
|
@ -860,15 +860,15 @@ bool NineChess::capture(int c, int p, long time_p /* = -1*/)
|
|||
|
||||
// 去子(设置禁点)
|
||||
if (currentRule.hasForbiddenPoint && context.stage == GAME_PLACING) {
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
revertHash(pos);
|
||||
#endif
|
||||
board_[pos] = '\x0f';
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
updateHash(pos);
|
||||
#endif
|
||||
} else { // 去子
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
revertHash(pos);
|
||||
#endif
|
||||
board_[pos] = '\x00';
|
||||
|
@ -1036,7 +1036,7 @@ bool NineChess::place(int pos)
|
|||
|
||||
board_[pos] = piece;
|
||||
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
updateHash(pos);
|
||||
#endif
|
||||
move_ = pos;
|
||||
|
@ -1114,11 +1114,11 @@ bool NineChess::place(int pos)
|
|||
// 移子
|
||||
move_ = (currentPos << 8) + pos;
|
||||
board_[pos] = board_[currentPos];
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
updateHash(pos);
|
||||
#endif
|
||||
board_[currentPos] = '\x00';
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
revertHash(currentPos);
|
||||
#endif
|
||||
currentPos = pos;
|
||||
|
@ -1184,15 +1184,15 @@ bool NineChess::capture(int pos)
|
|||
}
|
||||
|
||||
if (currentRule.hasForbiddenPoint && context.stage == GAME_PLACING) {
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
revertHash(pos);
|
||||
#endif
|
||||
board_[pos] = '\x0f';
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
updateHash(pos);
|
||||
#endif
|
||||
} else { // 去子
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
revertHash(pos);
|
||||
#endif
|
||||
board_[pos] = '\x00';
|
||||
|
@ -1206,7 +1206,7 @@ bool NineChess::capture(int pos)
|
|||
move_ = -pos;
|
||||
currentPos = 0;
|
||||
context.nPiecesNeedRemove--;
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
updateHash(pos);
|
||||
#endif
|
||||
//step++;
|
||||
|
@ -1515,6 +1515,9 @@ bool NineChess::win()
|
|||
context.stage = GAME_OVER;
|
||||
sprintf(cmdline, "Player1 win!");
|
||||
cmdlist.push_back(string(cmdline));
|
||||
#ifdef BOOK_LEARNING
|
||||
NineChessAi_ab::recordOpeningBookToHashMap(); // 暂时只对后手的失败记录到开局库
|
||||
#endif /* BOOK_LEARNING */
|
||||
return true;
|
||||
}
|
||||
// 如果摆满了,根据规则判断胜负
|
||||
|
@ -1550,6 +1553,9 @@ bool NineChess::win()
|
|||
context.stage = GAME_OVER;
|
||||
sprintf(cmdline, "Player2 no way to go. Player1 win!");
|
||||
cmdlist.push_back(string(cmdline));
|
||||
#ifdef BOOK_LEARNING
|
||||
NineChessAi_ab::recordOpeningBookToHashMap(); // 暂时只对后手的失败记录到开局库
|
||||
#endif /* BOOK_LEARNING */
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1745,7 +1751,7 @@ void NineChess::cleanForbiddenPoints()
|
|||
for (int j = 0; j < N_SEATS; j++) {
|
||||
pos = i * N_SEATS + j;
|
||||
if (board_[pos] == '\x0f') {
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
revertHash(pos);
|
||||
#endif
|
||||
board_[pos] = '\x00';
|
||||
|
@ -2294,7 +2300,7 @@ void NineChess::rotate(int degrees, bool cmdChange /*= true*/)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
|
||||
#if 0
|
||||
/*
|
||||
|
|
|
@ -184,7 +184,7 @@ public:
|
|||
*/
|
||||
int board[N_POINTS];
|
||||
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
// 局面的哈希值
|
||||
uint64_t hash;
|
||||
|
||||
|
@ -493,7 +493,7 @@ protected:
|
|||
bool place(int pos);
|
||||
bool capture(int pos);
|
||||
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
// hash相关
|
||||
uint64_t getHash();
|
||||
uint64_t revertHash(int pos);
|
||||
|
|
|
@ -20,7 +20,13 @@ using namespace CTSL;
|
|||
#ifdef HASH_MAP_ENABLE
|
||||
static constexpr int hashsize = 0x8000000; // 128M
|
||||
HashMap<uint64_t, NineChessAi_ab::HashValue> hashmap(hashsize);
|
||||
#endif
|
||||
#endif // HASH_MAP_ENABLE
|
||||
|
||||
#ifdef BOOK_LEARNING
|
||||
static constexpr int bookHashsize = 0x8000000; // 128M
|
||||
HashMap<uint64_t, NineChessAi_ab::HashValue> bookHashMap(bookHashsize);
|
||||
vector<uint64_t> openingBook;
|
||||
#endif // BOOK_LEARNING
|
||||
|
||||
NineChessAi_ab::NineChessAi_ab() :
|
||||
rootNode(nullptr),
|
||||
|
@ -63,8 +69,11 @@ struct NineChessAi_ab::Node *NineChessAi_ab::addNode(Node *parent, int value, in
|
|||
|
||||
newNode->pruned = false;
|
||||
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
newNode->hash = 0;
|
||||
#endif
|
||||
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
newNode->isHash = false;
|
||||
#endif
|
||||
|
||||
|
@ -394,12 +403,17 @@ 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)) {
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
clearHashMap();
|
||||
#endif // HASH_MAP_ENABLE
|
||||
|
||||
#ifdef BOOK_LEARNING
|
||||
//clearBookHashMap();
|
||||
//openingBook.clear();
|
||||
#endif // BOOK_LEARNING
|
||||
}
|
||||
#endif
|
||||
|
||||
this->chess_ = chess;
|
||||
chessTemp = chess;
|
||||
|
@ -610,6 +624,19 @@ int NineChessAi_ab::alphaBetaPruning(int depth)
|
|||
|
||||
time1.start();
|
||||
|
||||
#ifdef BOOK_LEARNING
|
||||
if (chess_.getStage() == NineChess::GAME_PLACING)
|
||||
{
|
||||
if (chess_.context.nPiecesInHand_1 < 8) {
|
||||
// 不是一开始就记录到开局库
|
||||
openingBook.push_back(chess_.getHash());
|
||||
} else {
|
||||
// 暂时在此处清空开局库
|
||||
openingBook.clear();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MOVE_PRIORITY_TABLE_SUPPORT
|
||||
#ifdef RANDOM_MOVE
|
||||
shuffleMovePriorityTable();
|
||||
|
@ -654,7 +681,12 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
|
|||
// 子节点的最优着法
|
||||
int bestMove = 0;
|
||||
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
#ifdef BOOK_LEARNING
|
||||
// 是否在开局库中出现过
|
||||
bool hitBook = false;
|
||||
#endif
|
||||
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
// 哈希值
|
||||
HashValue hashValue;
|
||||
memset(&hashValue, 0, sizeof(hashValue));
|
||||
|
@ -665,7 +697,19 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
|
|||
// 获取哈希值
|
||||
uint64_t hash = chessTemp.getHash();
|
||||
node->hash = hash;
|
||||
#endif
|
||||
|
||||
#ifdef BOOK_LEARNING
|
||||
// 检索开局库
|
||||
if (findBookHash(hash, hashValue)) {
|
||||
if (chessContext->turn == NineChess::PLAYER2) {
|
||||
// 是否需对后手扣分
|
||||
hitBook = true;
|
||||
}
|
||||
}
|
||||
#endif /* BOOK_LEARNING */
|
||||
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
// 检索 hashmap
|
||||
//hashMapMutex.lock();
|
||||
|
||||
|
@ -729,8 +773,6 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
|
|||
|
||||
minMax = chessTemp.whosTurn() == NineChess::PLAYER1 ? -INF_VALUE : INF_VALUE;
|
||||
|
||||
|
||||
|
||||
if (alpha >= beta) {
|
||||
node->value = hashValue.value;
|
||||
return node->value;
|
||||
|
@ -940,6 +982,12 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
|
|||
#endif
|
||||
#endif /* HASH_MAP_ENABLE */
|
||||
|
||||
#ifdef BOOK_LEARNING
|
||||
if (hitBook) {
|
||||
node->value++;
|
||||
}
|
||||
#endif
|
||||
|
||||
// 返回
|
||||
return node->value;
|
||||
}
|
||||
|
@ -1088,7 +1136,7 @@ bool NineChessAi_ab::findHash(uint64_t hash, HashValue &hashValue)
|
|||
if (iter != hashmap.end())
|
||||
return iter;
|
||||
|
||||
// 变换局面,查找hash
|
||||
// 变换局面,查找hash (废弃)
|
||||
chessTempShift = chessTemp;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (i)
|
||||
|
@ -1108,6 +1156,10 @@ bool NineChessAi_ab::findHash(uint64_t hash, HashValue &hashValue)
|
|||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
|
||||
int NineChessAi_ab::recordHash(const HashValue &hashValue)
|
||||
{
|
||||
//hashMapMutex.lock();
|
||||
|
@ -1156,3 +1208,46 @@ void NineChessAi_ab::clearHashMap()
|
|||
//hashMapMutex.unlock();
|
||||
}
|
||||
#endif /* HASH_MAP_ENABLE */
|
||||
|
||||
#ifdef BOOK_LEARNING
|
||||
|
||||
bool NineChessAi_ab::findBookHash(uint64_t hash, HashValue &hashValue)
|
||||
{
|
||||
return bookHashMap.find(hash, hashValue);
|
||||
}
|
||||
|
||||
int NineChessAi_ab::recordBookHash(const HashValue &hashValue)
|
||||
{
|
||||
//hashMapMutex.lock();
|
||||
bookHashMap.insert(hashValue.hash, hashValue);
|
||||
//hashMapMutex.unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NineChessAi_ab::clearBookHashMap()
|
||||
{
|
||||
//hashMapMutex.lock();
|
||||
bookHashMap.clear();
|
||||
//hashMapMutex.unlock();
|
||||
}
|
||||
|
||||
void NineChessAi_ab::recordOpeningBookToHashMap()
|
||||
{
|
||||
HashValue hashValue;
|
||||
|
||||
for (auto iter = openingBook.begin(); iter != openingBook.end(); ++iter)
|
||||
{
|
||||
#if 0
|
||||
if (findBookHash(*iter, hashValue))
|
||||
{
|
||||
}
|
||||
#endif
|
||||
memset(&hashValue, 0, sizeof(HashValue));
|
||||
hashValue.hash = *iter;
|
||||
recordBookHash(hashValue); // 暂时使用直接覆盖策略
|
||||
}
|
||||
|
||||
openingBook.clear();
|
||||
}
|
||||
#endif // BOOK_LEARNING
|
||||
|
|
|
@ -38,8 +38,10 @@ public:
|
|||
struct Node* parent; // 父节点
|
||||
size_t id; // 结点编号
|
||||
bool pruned; // 是否在此处剪枝
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
uint64_t hash; // 哈希值
|
||||
#endif
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
bool isHash; // 是否从 Hash 读取
|
||||
#endif /* HASH_MAP_ENABLE */
|
||||
#ifdef DEBUG_AB_TREE
|
||||
|
@ -79,7 +81,7 @@ public:
|
|||
#endif
|
||||
};
|
||||
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
// 定义哈希值的类型
|
||||
enum HashType
|
||||
{
|
||||
|
@ -98,7 +100,7 @@ public:
|
|||
enum HashType type;
|
||||
int bestMove;
|
||||
};
|
||||
#endif /* HASH_MAP_ENABLE */
|
||||
#endif
|
||||
|
||||
public:
|
||||
NineChessAi_ab();
|
||||
|
@ -118,7 +120,7 @@ public:
|
|||
// 返回最佳走法的命令行
|
||||
const char *bestMove();
|
||||
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
#if ((defined HASH_MAP_ENABLE) || (defined BOOK_LEARNING))
|
||||
// 清空哈希表
|
||||
void clearHashMap();
|
||||
#endif
|
||||
|
@ -127,6 +129,13 @@ public:
|
|||
static bool nodeLess(const Node *first, const Node *second);
|
||||
static bool nodeGreater(const Node *first, const Node *second);
|
||||
|
||||
#ifdef BOOK_LEARNING
|
||||
bool findBookHash(uint64_t hash, HashValue &hashValue);
|
||||
static int recordBookHash(const HashValue &hashValue);
|
||||
void clearBookHashMap();
|
||||
static void recordOpeningBookToHashMap();
|
||||
#endif // BOOK_LEARNING
|
||||
|
||||
protected:
|
||||
// 生成所有合法的着法并建立子节点
|
||||
void generateLegalMoves(Node *node, int bestMove);
|
||||
|
@ -170,7 +179,7 @@ protected:
|
|||
// 插入哈希表
|
||||
int recordHash(const HashValue &hashValue);
|
||||
int recordHash(int value, int depth, HashType type, uint64_t hash, int bestMove);
|
||||
#endif
|
||||
#endif // HASH_MAP_ENABLE
|
||||
|
||||
private:
|
||||
// 原始模型
|
||||
|
|
Loading…
Reference in New Issue