Merge branch 'book'

合并开局学习相关提交,但暂不开启宏,因未完善 (棋力越下越弱)
This commit is contained in:
CalciteM Team 2019-07-20 17:36:04 +08:00
commit 5aff5d8d29
5 changed files with 148 additions and 36 deletions

View File

@ -11,6 +11,8 @@
#define HASH_MAP_ENABLE
//#define BOOK_LEARNING
//#define DONOT_DELETE_TREE
#define MOVE_PRIORITY_TABLE_SUPPORT

View File

@ -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
/*

View File

@ -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);

View File

@ -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

View File

@ -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:
// 原始模型