parent
03294e1557
commit
702a562bbd
|
@ -18,6 +18,7 @@ CONFIG += C++11 \
|
|||
INCLUDEPATH += src
|
||||
|
||||
SOURCES += \
|
||||
src/hashmap.cpp \
|
||||
src/main.cpp \
|
||||
src/boarditem.cpp \
|
||||
src/gamecontroller.cpp \
|
||||
|
@ -36,6 +37,7 @@ HEADERS += \
|
|||
src/gamescene.h \
|
||||
src/gameview.h \
|
||||
src/graphicsconst.h \
|
||||
src/hashmap.h \
|
||||
src/ninechess.h \
|
||||
src/ninechessai_ab.h \
|
||||
src/ninechesswindow.h \
|
||||
|
|
|
@ -378,6 +378,7 @@
|
|||
<ClCompile Include="src\gamecontroller.cpp" />
|
||||
<ClCompile Include="src\gamescene.cpp" />
|
||||
<ClCompile Include="src\gameview.cpp" />
|
||||
<ClCompile Include="src\hashmap.cpp" />
|
||||
<ClCompile Include="src\main.cpp" />
|
||||
<ClCompile Include="src\ninechess.cpp" />
|
||||
<ClCompile Include="src\ninechessai_ab.cpp" />
|
||||
|
@ -426,6 +427,7 @@
|
|||
</QtMoc>
|
||||
<ClInclude Include="src\config.h" />
|
||||
<ClInclude Include="src\graphicsconst.h" />
|
||||
<ClInclude Include="src\hashmap.h" />
|
||||
<ClInclude Include="src\ninechess.h" />
|
||||
<QtMoc Include="src\ninechesswindow.h">
|
||||
<IncludePath Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\GeneratedFiles\$(ConfigurationName);.\GeneratedFiles;.;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include;debug;\include;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\mkspecs\win32-msvc;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtWidgets;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtCore;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtGui;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtANGLE;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtMultimedia;D:\Qt\Qt5.11.0\5.11.0\msvc2017_64\include\QtNetwork;%(AdditionalIncludeDirectories)</IncludePath>
|
||||
|
|
|
@ -84,6 +84,9 @@
|
|||
<ClCompile Include="src\ninechessai_ab.cpp">
|
||||
<Filter>Model</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\hashmap.cpp">
|
||||
<Filter>Model</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="resource.h">
|
||||
|
@ -110,6 +113,9 @@
|
|||
<ClInclude Include="src\config.h">
|
||||
<Filter>Control</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\hashmap.h">
|
||||
<Filter>Model</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CustomBuild Include="debug\moc_predefs.h.cbt">
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
#include "hashmap.h"
|
||||
|
||||
template <typename T>
|
||||
HashMap<T>::HashMap():
|
||||
capacity(0),
|
||||
size(0),
|
||||
pool(nullptr)
|
||||
{
|
||||
this->capacity = 0x20000000; // TODO
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
HashMap<T>::HashMap(size_t capacity)
|
||||
{
|
||||
this->capacity = capacity;
|
||||
this->size = 0;
|
||||
construct();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
HashMap<T>::~HashMap()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool HashMap<T>::construct()
|
||||
{
|
||||
pool = new T[capacity];
|
||||
|
||||
if (pool == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T& HashMap<T>::at(uint64_t i)
|
||||
{
|
||||
if (i >= capacity) {
|
||||
qDebug() << "Ë÷Òý³¬¹ý×î´óÖµ";
|
||||
return pool[0];
|
||||
}
|
||||
return pool[i];
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
size_t HashMap<T>::getSize()
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
size_t HashMap<T>::getCapacity()
|
||||
{
|
||||
return capacity;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
uint64_t HashMap<T>::hashToAddr(uint64_t hash)
|
||||
{
|
||||
return hash << 32 >> 32;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void HashMap<T>::insert(uint64_t hash, const T &hashValue)
|
||||
{
|
||||
uint64_t addr = hashToAddr(hash);
|
||||
|
||||
pool[addr] = hashValue;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void HashMap<T>::clear()
|
||||
{
|
||||
delete[] pool;
|
||||
pool = nullptr;
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
#ifndef HASHMAP_H
|
||||
|
||||
#include <limits>
|
||||
#include <qDebug>
|
||||
|
||||
template <typename T>
|
||||
class HashMap
|
||||
{
|
||||
public:
|
||||
HashMap();
|
||||
HashMap(size_t capacity);
|
||||
~HashMap();
|
||||
|
||||
enum FindResult
|
||||
{
|
||||
HASHMAP_NOTFOUND = INT32_MAX,
|
||||
};
|
||||
|
||||
T& at(uint64_t i);
|
||||
|
||||
T& operator[](uint64_t hash)
|
||||
{
|
||||
uint64_t addr = hashToAddr(hash);
|
||||
|
||||
return pool[addr];
|
||||
}
|
||||
|
||||
T &find(uint64_t hash)
|
||||
{
|
||||
uint64_t addr = hashToAddr(hash);
|
||||
|
||||
return pool[addr];
|
||||
}
|
||||
|
||||
size_t getSize();
|
||||
size_t getCapacity();
|
||||
|
||||
void clear();
|
||||
|
||||
void insert(uint64_t hash, const T &hashValue);
|
||||
|
||||
protected:
|
||||
private:
|
||||
size_t capacity;
|
||||
size_t size;
|
||||
|
||||
T *pool;
|
||||
|
||||
bool construct();
|
||||
|
||||
uint64_t hashToAddr(uint64_t hash);
|
||||
};
|
||||
|
||||
|
||||
#endif // HASHMAP_H
|
|
@ -178,11 +178,12 @@ NineChess::~NineChess()
|
|||
|
||||
void NineChess::constructHash()
|
||||
{
|
||||
context.hashCheckCode = 0;
|
||||
context.hash = 0ull;
|
||||
context.hashCheckCode = 0ull;
|
||||
|
||||
#if 0
|
||||
gameMovingHash = rand64();
|
||||
player2sTurnHash = rand64();
|
||||
context.gameMovingHash = rand64();
|
||||
context.actionCaptureHash = rand64();
|
||||
context.player2sTurnHash = rand64();
|
||||
|
||||
uint64_t zobrist[N_POINTS][POINT_TYPE_COUNT];
|
||||
|
||||
|
@ -191,7 +192,6 @@ void NineChess::constructHash()
|
|||
zobrist[p][t] = rand64();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
NineChess::Player NineChess::getOpponent(NineChess::Player player)
|
||||
|
@ -324,7 +324,8 @@ 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 hashCheckCode)
|
||||
int nPiecesInHand_1, int nPiecesInHand_2, int nPiecesNeedRemove,
|
||||
uint64_t hash, uint64_t hashCheckCode)
|
||||
{
|
||||
// 有效性判断
|
||||
if (maxStepsLedToDraw < 0 || maxTimeLedToLose < 0 || initialStep < 0 ||
|
||||
|
@ -390,9 +391,11 @@ bool NineChess::setContext(const struct Rule *rule, int maxStepsLedToDraw, int m
|
|||
// 当前棋局(3×8)
|
||||
if (board == nullptr) {
|
||||
memset(context.board, 0, sizeof(context.board));
|
||||
context.hashCheckCode = 0;
|
||||
context.hash = 0ull;
|
||||
context.hashCheckCode = 0ull;
|
||||
} else {
|
||||
memcpy(context.board, board, sizeof(context.board));
|
||||
context.hash = hash;
|
||||
context.hashCheckCode = hashCheckCode;
|
||||
}
|
||||
|
||||
|
@ -491,7 +494,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 &hashCheckCode)
|
||||
uint64_t &hash, uint64_t &hashCheckCode)
|
||||
{
|
||||
rule = this->currentRule;
|
||||
step = this->currentStep;
|
||||
|
@ -544,7 +547,8 @@ bool NineChess::reset()
|
|||
// 用时置零
|
||||
elapsedMS_1 = elapsedMS_2 = 0;
|
||||
|
||||
// 哈希校验码归零
|
||||
// 哈希以及哈希校验码归零
|
||||
context.hash = 0;
|
||||
context.hashCheckCode = 0;
|
||||
|
||||
// 提示
|
||||
|
@ -699,7 +703,7 @@ bool NineChess::place(int c, int p, long time_p /* = -1*/)
|
|||
}
|
||||
|
||||
board_[pos] = piece;
|
||||
updateHashCheckCode(pos);
|
||||
updateHash(pos);
|
||||
move_ = pos;
|
||||
player_ms = update(time_p);
|
||||
sprintf(cmdline, "(%1u,%1u) %02u:%02u.%03u",
|
||||
|
@ -788,9 +792,9 @@ 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];
|
||||
updateHashCheckCode(pos);
|
||||
updateHash(pos);
|
||||
board_[currentPos] = '\x00';
|
||||
updateHashCheckCode(currentPos);
|
||||
updateHash(currentPos);
|
||||
currentPos = pos;
|
||||
currentStep++;
|
||||
n = addMills(currentPos);
|
||||
|
@ -876,7 +880,7 @@ bool NineChess::capture(int c, int p, long time_p /* = -1*/)
|
|||
currentPos = 0;
|
||||
context.nPiecesNeedRemove--;
|
||||
currentStep++;
|
||||
updateHashCheckCode(pos);
|
||||
updateHash(pos);
|
||||
// 去子完成
|
||||
|
||||
// 如果决出胜负
|
||||
|
@ -1026,7 +1030,7 @@ bool NineChess::place(int pos)
|
|||
}
|
||||
|
||||
board_[pos] = piece;
|
||||
updateHashCheckCode(pos);
|
||||
updateHash(pos);
|
||||
move_ = pos;
|
||||
currentPos = pos;
|
||||
//step++;
|
||||
|
@ -1102,9 +1106,9 @@ bool NineChess::place(int pos)
|
|||
// 移子
|
||||
move_ = (currentPos << 8) + pos;
|
||||
board_[pos] = board_[currentPos];
|
||||
updateHashCheckCode(pos);
|
||||
updateHash(pos);
|
||||
board_[currentPos] = '\x00';
|
||||
updateHashCheckCode(currentPos);
|
||||
updateHash(currentPos);
|
||||
currentPos = pos;
|
||||
//step++;
|
||||
n = addMills(currentPos);
|
||||
|
@ -1181,7 +1185,7 @@ bool NineChess::capture(int pos)
|
|||
move_ = -pos;
|
||||
currentPos = 0;
|
||||
context.nPiecesNeedRemove--;
|
||||
updateHashCheckCode(pos);
|
||||
updateHash(pos);
|
||||
//step++;
|
||||
// 去子完成
|
||||
|
||||
|
@ -1286,16 +1290,21 @@ bool NineChess::choose(int pos)
|
|||
return false;
|
||||
}
|
||||
|
||||
uint64_t NineChess::getHash()
|
||||
{
|
||||
return context.hash;
|
||||
}
|
||||
|
||||
uint64_t NineChess::getHashCheckCode()
|
||||
{
|
||||
return context.hashCheckCode;
|
||||
}
|
||||
|
||||
// hash函数,对应可重复去子的规则
|
||||
uint64_t NineChess::updateHashCheckCode(int pos)
|
||||
uint64_t NineChess::updateHash(int pos)
|
||||
{
|
||||
/*
|
||||
* hash校验码各数据位详解(并无冲突,是算法用到的棋局数据的完全表示)
|
||||
* hashCheckCode 各数据位详解(并无冲突,是算法用到的棋局数据的完全表示)
|
||||
* 56-63位:空白不用,全为0
|
||||
* 55位:轮流标识,0为先手,1为后手
|
||||
* 54位:动作标识,落子(选子移动)为0,1为去子
|
||||
|
@ -1305,28 +1314,32 @@ uint64_t NineChess::updateHashCheckCode(int pos)
|
|||
* 0-3位:player1的手棋数,不需要player2的(可计算出)
|
||||
*/
|
||||
|
||||
#if 0
|
||||
uint64_t hash = 0ull;
|
||||
|
||||
// TODO: 本函数效率低下,啥时调用?
|
||||
for (int i = POS_BEGIN; i < POS_END; i++) {
|
||||
hash |= board_[i] & 0x30;
|
||||
hash <<= 2;
|
||||
// hash ^= context.zobrist[i][pointType]; // TODO: 待完善
|
||||
}
|
||||
#endif
|
||||
|
||||
uint64_t temp = board_[pos] & 0x30 >> 4;
|
||||
context.hashCheckCode |= (temp) << ((pos - 8) * 2 + 6);
|
||||
// TODO: context.hash =
|
||||
|
||||
if (context.turn == PLAYER2)
|
||||
if (context.turn == PLAYER2) {
|
||||
context.hashCheckCode |= 1ull << 55;
|
||||
context.hash ^= context.player2sTurnHash;
|
||||
}
|
||||
|
||||
if (context.action == ACTION_CAPTURE)
|
||||
if (context.action == ACTION_CAPTURE) {
|
||||
context.hashCheckCode |= 1ull << 54;
|
||||
context.hash ^= context.actionCaptureHash;
|
||||
}
|
||||
|
||||
context.hashCheckCode |= (uint64_t)context.nPiecesNeedRemove << 4;
|
||||
context.hashCheckCode |= context.nPiecesInHand_1;
|
||||
// TODO: hash 应该 不需要
|
||||
|
||||
return context.hashCheckCode;
|
||||
return context.hashCheckCode; // TODO: 返回什么
|
||||
}
|
||||
|
||||
bool NineChess::giveup(Player loser)
|
||||
|
@ -1762,7 +1775,7 @@ void NineChess::cleanForbiddenPoints()
|
|||
pos = i * N_SEATS + j;
|
||||
if (board_[pos] == '\x0f') {
|
||||
board_[pos] = '\x00';
|
||||
updateHashCheckCode(pos);
|
||||
updateHash(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -182,8 +182,23 @@ public:
|
|||
// 局面哈希的校验码,校验码相同 才能认为是同一局面
|
||||
uint64_t hashCheckCode;
|
||||
|
||||
// 局面的哈希值
|
||||
uint64_t hash;
|
||||
|
||||
// 哈希表中的地址, 为 hash 的后 16 位
|
||||
uint16_t hashAddr;
|
||||
|
||||
// 标记处于走子阶段的哈希
|
||||
uint16_t gameMovingHash;
|
||||
|
||||
// 吃子动作的哈希
|
||||
uint16_t actionCaptureHash;
|
||||
|
||||
// 标记轮到玩家2行棋的哈希
|
||||
uint16_t player2sTurnHash;
|
||||
|
||||
// Zobrist 数组
|
||||
//uint64_t zobrist[N_POINTS][POINT_TYPE_COUNT];
|
||||
uint64_t zobrist[N_POINTS][POINT_TYPE_COUNT];
|
||||
|
||||
// 局面阶段标识
|
||||
enum NineChess::GameStage stage;
|
||||
|
@ -269,13 +284,14 @@ public:
|
|||
int nPiecesInHand_1 = 12, // 玩家1剩余未放置子数
|
||||
int nPiecesInHand_2 = 12, // 玩家2剩余未放置子数
|
||||
int nPiecesNeedRemove = 0, // 尚待去除的子数
|
||||
uint64_t hashCheckCode = 0ull // Hash 为0
|
||||
uint64_t hash = 0ull, // 哈希值
|
||||
uint64_t hashCheckCode = 0ull // 哈希校验码
|
||||
);
|
||||
|
||||
// 获取棋局状态和棋盘上下文
|
||||
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 &hash, uint64_t &hashCheckCode);
|
||||
|
||||
// 获取当前规则
|
||||
const struct Rule *getRule() const
|
||||
|
@ -479,9 +495,10 @@ protected:
|
|||
bool place(int pos);
|
||||
bool capture(int pos);
|
||||
|
||||
// hash校验值相关
|
||||
// hash相关
|
||||
uint64_t getHash();
|
||||
uint64_t getHashCheckCode();
|
||||
uint64_t updateHashCheckCode(int pos);
|
||||
uint64_t updateHash(int pos);
|
||||
|
||||
private:
|
||||
// 当前使用的规则
|
||||
|
|
|
@ -3,17 +3,16 @@
|
|||
** Mail: liuweilhy@163.com
|
||||
** This file is part of the NineChess game.
|
||||
****************************************************************************/
|
||||
|
||||
#include "ninechessai_ab.h"
|
||||
#include <cmath>
|
||||
#include <time.h>
|
||||
#include <Qdebug>
|
||||
#include <QTime>
|
||||
#include <array>
|
||||
#include <random>
|
||||
#include <chrono>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <random>
|
||||
#include <chrono>
|
||||
#include <algorithm>
|
||||
|
||||
#include "ninechessai_ab.h"
|
||||
|
||||
NineChessAi_ab::NineChessAi_ab() :
|
||||
rootNode(nullptr),
|
||||
|
@ -31,14 +30,6 @@ NineChessAi_ab::~NineChessAi_ab()
|
|||
rootNode = nullptr;
|
||||
}
|
||||
|
||||
void NineChessAi_ab::clearHashMap()
|
||||
{
|
||||
hashMapMutex.lock();
|
||||
hashmap.clear();
|
||||
hashmap.reserve(maxHashCount);
|
||||
hashMapMutex.unlock();
|
||||
}
|
||||
|
||||
void NineChessAi_ab::buildRoot()
|
||||
{
|
||||
rootNode = addNode(nullptr, 0, 0, NineChess::NOBODY);
|
||||
|
@ -100,45 +91,48 @@ struct NineChessAi_ab::Node *NineChessAi_ab::addNode(Node *parent, int value, in
|
|||
}
|
||||
|
||||
// 静态hashmap初始化
|
||||
mutex NineChessAi_ab::hashMapMutex;
|
||||
unordered_map<uint64_t, NineChessAi_ab::HashValue> NineChessAi_ab::hashmap;
|
||||
//mutex NineChessAi_ab::hashMapMutex;
|
||||
//HashMap<NineChessAi_ab::HashValue> NineChessAi_ab::hashmap;
|
||||
|
||||
mutex hashMapMutex;
|
||||
HashMap<NineChessAi_ab::HashValue> hashmap;
|
||||
|
||||
#ifdef MOVE_PRIORITY_TABLE_SUPPORT
|
||||
#ifdef RANDOM_MOVE
|
||||
void NineChessAi_ab::shuffleMovePriorityTable()
|
||||
{
|
||||
array<int, 4> movePriorityTable0 = { 17, 19, 21, 23 }; // 中圈四个顶点 (星位)
|
||||
array<int, 4> movePriorityTable0 = { 17, 19, 21, 23 }; // 中圈四个顶点 (星位)
|
||||
array<int, 8> movePriorityTable1 = { 25, 27, 29, 31, 9, 11, 13, 15 }; // 外圈和内圈四个顶点
|
||||
array<int, 4> movePriorityTable2 = { 16, 18, 20, 22 }; // 中圈十字架
|
||||
array<int, 4> movePriorityTable3 = { 8, 10, 12, 14 }; // 内圈十字架
|
||||
array<int, 4> movePriorityTable4 = { 24, 26, 28, 30 }; // 外圈十字架
|
||||
|
||||
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
|
||||
|
||||
std::shuffle(movePriorityTable0.begin(), movePriorityTable0.end(), std::default_random_engine(seed));
|
||||
std::shuffle(movePriorityTable1.begin(), movePriorityTable1.end(), std::default_random_engine(seed));
|
||||
std::shuffle(movePriorityTable2.begin(), movePriorityTable2.end(), std::default_random_engine(seed));
|
||||
std::shuffle(movePriorityTable3.begin(), movePriorityTable3.end(), std::default_random_engine(seed));
|
||||
std::shuffle(movePriorityTable4.begin(), movePriorityTable4.end(), std::default_random_engine(seed));
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
movePriorityTable[i + 0] = movePriorityTable0[i];
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
movePriorityTable[i + 4] = movePriorityTable1[i];
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
movePriorityTable[i + 12] = movePriorityTable2[i];
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
movePriorityTable[i + 16] = movePriorityTable3[i];
|
||||
array<int, 4> movePriorityTable2 = { 16, 18, 20, 22 }; // 中圈十字架
|
||||
array<int, 4> movePriorityTable3 = { 8, 10, 12, 14 }; // 内圈十字架
|
||||
array<int, 4> movePriorityTable4 = { 24, 26, 28, 30 }; // 外圈十字架
|
||||
|
||||
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
|
||||
|
||||
std::shuffle(movePriorityTable0.begin(), movePriorityTable0.end(), std::default_random_engine(seed));
|
||||
std::shuffle(movePriorityTable1.begin(), movePriorityTable1.end(), std::default_random_engine(seed));
|
||||
std::shuffle(movePriorityTable2.begin(), movePriorityTable2.end(), std::default_random_engine(seed));
|
||||
std::shuffle(movePriorityTable3.begin(), movePriorityTable3.end(), std::default_random_engine(seed));
|
||||
std::shuffle(movePriorityTable4.begin(), movePriorityTable4.end(), std::default_random_engine(seed));
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
movePriorityTable[i + 0] = movePriorityTable0[i];
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
movePriorityTable[i + 20] = movePriorityTable4[i];
|
||||
for (int i = 0; i < 8; i++) {
|
||||
movePriorityTable[i + 4] = movePriorityTable1[i];
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
movePriorityTable[i + 12] = movePriorityTable2[i];
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
movePriorityTable[i + 16] = movePriorityTable3[i];
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
movePriorityTable[i + 20] = movePriorityTable4[i];
|
||||
}
|
||||
}
|
||||
#endif // #ifdef RANDOM_MOVE
|
||||
|
@ -187,7 +181,7 @@ void NineChessAi_ab::generateLegalMoves(Node *node)
|
|||
case NineChess::ACTION_PLACE:
|
||||
// 对于摆子阶段
|
||||
if (chessTemp.context.stage & (NineChess::GAME_PLACING | NineChess::GAME_NOTSTARTED)) {
|
||||
for (int i = 0; i < MOVE_PRIORITY_TABLE_SIZE; i++) {
|
||||
for (int i = 0; i < MOVE_PRIORITY_TABLE_SIZE; i++) {
|
||||
pos = movePriorityTable[i];
|
||||
if (!chessTemp.board_[pos]) {
|
||||
if (node == rootNode && chessTemp.context.stage == NineChess::GAME_NOTSTARTED) {
|
||||
|
@ -211,7 +205,7 @@ void NineChessAi_ab::generateLegalMoves(Node *node)
|
|||
for (int i = MOVE_PRIORITY_TABLE_SIZE - 1; i >= 0; i--) {
|
||||
#else
|
||||
for (int i = 0; i < MOVE_PRIORITY_TABLE_SIZE; i++) {
|
||||
#endif // MOVE_PRIORITY_TABLE_SUPPORT
|
||||
#endif // MOVE_PRIORITY_TABLE_SUPPORT
|
||||
oldPos = movePriorityTable[i];
|
||||
if (!chessTemp.choose(oldPos))
|
||||
continue;
|
||||
|
@ -246,7 +240,7 @@ void NineChessAi_ab::generateLegalMoves(Node *node)
|
|||
case NineChess::ACTION_CAPTURE:
|
||||
if (chessTemp.isAllInMills(opponent)) {
|
||||
// 全成三的情况
|
||||
for (int i = MOVE_PRIORITY_TABLE_SIZE - 1; i >= 0; i--) {
|
||||
for (int i = MOVE_PRIORITY_TABLE_SIZE - 1; i >= 0; i--) {
|
||||
pos = movePriorityTable[i];
|
||||
if (chessTemp.board_[pos] & opponent) {
|
||||
addNode(node, 0, -pos, chessTemp.context.turn);
|
||||
|
@ -254,7 +248,7 @@ void NineChessAi_ab::generateLegalMoves(Node *node)
|
|||
}
|
||||
} else {
|
||||
// 不是全成三的情况
|
||||
for (int i = MOVE_PRIORITY_TABLE_SIZE - 1; i >= 0; i--) {
|
||||
for (int i = MOVE_PRIORITY_TABLE_SIZE - 1; i >= 0; i--) {
|
||||
pos = movePriorityTable[i];
|
||||
if (chessTemp.board_[pos] & opponent) {
|
||||
if (chessTemp.getRule()->allowRemoveMill || !chessTemp.isInMills(pos)) {
|
||||
|
@ -626,26 +620,29 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
|
|||
#ifdef HASH_MAP_ENABLE
|
||||
// 检索 hashmap
|
||||
uint64_t hashCheckCode = chessTemp.getHashCheckCode();
|
||||
node->hash = hashCheckCode;
|
||||
node->hashCheckCode = hashCheckCode;
|
||||
|
||||
uint64_t hash = chessTemp.getHash();
|
||||
node->hash = hash;
|
||||
|
||||
hashMapMutex.lock();
|
||||
|
||||
auto iter = findHash(hashCheckCode);
|
||||
HashValue hashValue = findHash(hash);
|
||||
|
||||
if (node != rootNode &&
|
||||
iter != hashmap.end() &&
|
||||
iter->second.depth >= depth) {
|
||||
hashValue.hash == hash &&
|
||||
hashValue.depth >= depth) {
|
||||
#ifdef DEBUG_AB_TREE
|
||||
node->isHash = true;
|
||||
#endif
|
||||
|
||||
// TODO: 处理 Alpha/Beta 确切值
|
||||
node->value = iter->second.value;
|
||||
node->value = hashValue.value;
|
||||
|
||||
if (chessContext->turn == NineChess::PLAYER1)
|
||||
node->value += iter->second.depth - depth;
|
||||
node->value += hashValue.depth - depth;
|
||||
else
|
||||
node->value -= iter->second.depth - depth;
|
||||
node->value -= hashValue.depth - depth;
|
||||
|
||||
hashMapMutex.unlock();
|
||||
hashHitCount++;
|
||||
|
@ -673,7 +670,14 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
|
|||
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
// 记录确切的哈希值
|
||||
recordHash(hashCheckCode, depth, node->value, hashfEXACT);
|
||||
HashValue newHashValue;
|
||||
newHashValue.alpha = alpha;
|
||||
newHashValue.beta = beta;
|
||||
newHashValue.depth = depth;
|
||||
newHashValue.type = hashfEXACT;
|
||||
newHashValue.hash = hash;
|
||||
newHashValue.value = node->value;
|
||||
recordHash(newHashValue);
|
||||
#endif
|
||||
|
||||
return node->value;
|
||||
|
@ -698,7 +702,14 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
|
|||
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
// 记录确切的哈希值
|
||||
recordHash(hashCheckCode, depth, node->value, hashfEXACT);
|
||||
HashValue newHashValue;
|
||||
newHashValue.alpha = alpha;
|
||||
newHashValue.beta = beta;
|
||||
newHashValue.depth = depth;
|
||||
newHashValue.type = hashfEXACT;
|
||||
newHashValue.hash = hash;
|
||||
newHashValue.value = node->value;
|
||||
recordHash(newHashValue);
|
||||
#endif
|
||||
|
||||
return node->value;
|
||||
|
@ -794,18 +805,25 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
|
|||
#endif // DONOT_DELETE_TREE
|
||||
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
if (iter == hashmap.end()) {
|
||||
if (hashValue.hash != hash) {
|
||||
// 添加到hashmap
|
||||
recordHash(hashCheckCode, depth, node->value, hashf);
|
||||
HashValue newHashValue;
|
||||
newHashValue.alpha = alpha;
|
||||
newHashValue.beta = beta;
|
||||
newHashValue.depth = depth;
|
||||
newHashValue.type = hashf;
|
||||
newHashValue.hash = hash;
|
||||
newHashValue.value = node->value;
|
||||
recordHash(newHashValue);
|
||||
}
|
||||
// 更新更深层数据
|
||||
else {
|
||||
//hashMapMutex.lock();
|
||||
//if (iter->second.depth < depth) {
|
||||
//iter->second.value = node->value;
|
||||
//iter->second.depth = depth;
|
||||
//}
|
||||
//hashMapMutex.unlock();
|
||||
hashMapMutex.lock();
|
||||
if (hashValue.depth < depth) {
|
||||
hashValue.value = node->value;
|
||||
hashValue.depth = depth;
|
||||
}
|
||||
hashMapMutex.unlock();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -816,20 +834,11 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
|
|||
return node->value;
|
||||
}
|
||||
|
||||
int NineChessAi_ab::recordHash(uint64_t hash, int16_t depth, int value, enum HashType type)
|
||||
int NineChessAi_ab::recordHash(const HashValue &hashValue)
|
||||
{
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
hashMapMutex.lock();
|
||||
|
||||
HashValue hashValue;
|
||||
|
||||
hashValue.value = value;
|
||||
hashValue.depth = depth;
|
||||
hashValue.type = type;
|
||||
|
||||
if (hashmap.size() <= maxHashCount)
|
||||
hashmap.insert({ hash, hashValue });
|
||||
|
||||
hashmap.insert(hashValue.hash, hashValue);
|
||||
hashMapMutex.unlock();
|
||||
#endif // HASH_MAP_ENABLE
|
||||
|
||||
|
@ -931,10 +940,11 @@ const char *NineChessAi_ab::move2string(int move)
|
|||
return cmdline;
|
||||
}
|
||||
|
||||
unordered_map<uint64_t, NineChessAi_ab::HashValue>::iterator NineChessAi_ab::findHash(uint64_t hash)
|
||||
NineChessAi_ab::HashValue NineChessAi_ab::findHash(uint64_t hash)
|
||||
{
|
||||
auto iter = hashmap.find(hash);
|
||||
NineChessAi_ab::HashValue hashValue = hashmap.find(hash);
|
||||
|
||||
// TODO: 变换局面
|
||||
#if 0
|
||||
if (iter != hashmap.end())
|
||||
return iter;
|
||||
|
@ -958,5 +968,12 @@ unordered_map<uint64_t, NineChessAi_ab::HashValue>::iterator NineChessAi_ab::fin
|
|||
}
|
||||
#endif
|
||||
|
||||
return iter;
|
||||
return hashValue;
|
||||
}
|
||||
|
||||
void NineChessAi_ab::clearHashMap()
|
||||
{
|
||||
hashMapMutex.lock();
|
||||
hashmap.clear();
|
||||
hashMapMutex.unlock();
|
||||
}
|
||||
|
|
|
@ -9,13 +9,13 @@
|
|||
|
||||
#include <list>
|
||||
#include <stack>
|
||||
#include <unordered_map>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <Qdebug>
|
||||
#include <array>
|
||||
|
||||
#include "ninechess.h"
|
||||
#include "hashmap.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -39,8 +39,11 @@ public:
|
|||
// 定义哈希表的值
|
||||
struct HashValue
|
||||
{
|
||||
int16_t value;
|
||||
int16_t depth;
|
||||
int value;
|
||||
int depth;
|
||||
int alpha;
|
||||
int beta;
|
||||
uint64_t hash;
|
||||
enum HashType type;
|
||||
};
|
||||
|
||||
|
@ -55,6 +58,7 @@ public:
|
|||
size_t id; // 结点编号
|
||||
int rand; // 随机数,对于 value 一致的结点随机排序用
|
||||
uint64_t hash;
|
||||
uint64_t hashCheckCode;
|
||||
bool isHash; // 是否从 Hash 读取
|
||||
bool pruned; // 是否在此处剪枝
|
||||
#ifdef DEBUG_AB_TREE
|
||||
|
@ -77,19 +81,19 @@ public:
|
|||
#endif /* DEBUG_AB_TREE */
|
||||
|
||||
#if 0
|
||||
bool operator < (const Node &another) const
|
||||
{
|
||||
return this->value < another.value;
|
||||
bool operator < (const Node &another) const
|
||||
{
|
||||
return this->value < another.value;
|
||||
}
|
||||
|
||||
bool operator > (const Node &another) const
|
||||
{
|
||||
return this->value > another.value;
|
||||
bool operator > (const Node &another) const
|
||||
{
|
||||
return this->value > another.value;
|
||||
}
|
||||
|
||||
bool operator == (const Node &another) const
|
||||
{
|
||||
return this->value == another.value;
|
||||
bool operator == (const Node &another) const
|
||||
{
|
||||
return this->value == another.value;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
@ -136,7 +140,7 @@ protected:
|
|||
struct Node *addNode(Node *parent, int value, NineChess::move_t move, enum NineChess::Player player);
|
||||
|
||||
// 插入哈希表
|
||||
int recordHash(uint64_t hash, int16_t depth, int value, enum HashType type);
|
||||
int recordHash(const HashValue &hashValue);
|
||||
|
||||
// 评价函数
|
||||
int evaluate(Node *node);
|
||||
|
@ -157,8 +161,8 @@ protected:
|
|||
#endif
|
||||
#endif
|
||||
|
||||
// 判断是否在哈希表中
|
||||
unordered_map<uint64_t, NineChessAi_ab::HashValue>::iterator findHash(uint64_t hash);
|
||||
// 查找哈希表
|
||||
HashValue findHash(uint64_t hash);
|
||||
|
||||
private:
|
||||
// 原始模型
|
||||
|
@ -190,12 +194,6 @@ private:
|
|||
// 标识,用于跳出剪枝算法,立即返回
|
||||
bool requiredQuit;
|
||||
|
||||
// 互斥锁
|
||||
static mutex hashMapMutex;
|
||||
|
||||
// 局面数据哈希表
|
||||
static unordered_map<uint64_t, HashValue> hashmap;
|
||||
|
||||
#ifdef MOVE_PRIORITY_TABLE_SUPPORT
|
||||
array<int, NineChess::N_RINGS *NineChess::N_SEATS> movePriorityTable;
|
||||
#endif // MOVE_PRIORITY_TABLE_SUPPORT
|
||||
|
@ -214,4 +212,7 @@ private:
|
|||
char cmdline[32];
|
||||
};
|
||||
|
||||
extern mutex hashMapMutex;
|
||||
extern HashMap<NineChessAi_ab::HashValue> hashmap;
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue