parent
ae247bad52
commit
d38200dce5
|
@ -1,13 +1,13 @@
|
||||||
#ifndef CONFIG_H
|
#ifndef CONFIG_H
|
||||||
#define CONFIG_H
|
#define CONFIG_H
|
||||||
|
|
||||||
//#define DEBUG
|
#define DEBUG
|
||||||
|
|
||||||
#define DEAL_WITH_HORIZON_EFFECT
|
//#define DEAL_WITH_HORIZON_EFFECT
|
||||||
|
|
||||||
//#define RANDOM_BEST_MOVE
|
//#define RANDOM_BEST_MOVE
|
||||||
|
|
||||||
//#define HASH_MAP_ENABLE
|
#define HASH_MAP_ENABLE
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
#define DONOT_PLAY_SOUND
|
#define DONOT_PLAY_SOUND
|
||||||
|
|
|
@ -112,15 +112,20 @@ const int NineChess::onBoard[(N_RINGS + 2) * N_SEATS] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
// 着法表
|
// 着法表
|
||||||
int NineChess::moveTable[(N_RINGS + 2) * N_SEATS][N_MOVE_DIRECTIONS] = { 0 };
|
int NineChess::moveTable[N_POINTS][N_MOVE_DIRECTIONS] = { 0 };
|
||||||
|
|
||||||
// 成三表
|
// 成三表
|
||||||
int NineChess::millTable[(N_RINGS + 2) * N_SEATS][N_DIRECTIONS][N_RINGS - 1] = { 0 };
|
int NineChess::millTable[N_POINTS][N_DIRECTIONS][N_RINGS - 1] = { 0 };
|
||||||
|
|
||||||
NineChess::NineChess()
|
NineChess::NineChess()
|
||||||
{
|
{
|
||||||
// 单独提出 board,免得每次都写 context.board;
|
// 单独提出 board 等数据,免得每次都写 context.board;
|
||||||
board_ = context.board;
|
board_ = context.board;
|
||||||
|
//hash_ = &context.hash;
|
||||||
|
//zobrist_ = &context.zobrist;
|
||||||
|
|
||||||
|
// 创建哈希数据
|
||||||
|
constructHash();
|
||||||
|
|
||||||
// 默认选择第1号规则,即“打三棋”
|
// 默认选择第1号规则,即“打三棋”
|
||||||
setContext(&RULES[1]);
|
setContext(&RULES[1]);
|
||||||
|
@ -171,6 +176,24 @@ NineChess::~NineChess()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NineChess::constructHash()
|
||||||
|
{
|
||||||
|
context.hash = 0;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
gameMovingHash = rand64();
|
||||||
|
player2sTurnHash = rand64();
|
||||||
|
|
||||||
|
uint64_t zobrist[N_POINTS][POINT_TYPE_COUNT];
|
||||||
|
|
||||||
|
for (int p = 0; p < N_POINTS; p++) {
|
||||||
|
for (int t = NineChess::POINT_TYPE_EMPTY; t <= NineChess::POINT_TYPE_FORBIDDEN; t++) {
|
||||||
|
zobrist[p][t] = rand64();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
NineChess::Player NineChess::getOpponent(NineChess::Player player)
|
NineChess::Player NineChess::getOpponent(NineChess::Player player)
|
||||||
{
|
{
|
||||||
switch (player)
|
switch (player)
|
||||||
|
@ -301,7 +324,7 @@ void NineChess::createMillTable()
|
||||||
// 设置棋局状态和棋盘数据,用于初始化
|
// 设置棋局状态和棋盘数据,用于初始化
|
||||||
bool NineChess::setContext(const struct Rule *rule, int maxStepsLedToDraw, int maxTimeLedToLose,
|
bool NineChess::setContext(const struct Rule *rule, int maxStepsLedToDraw, int maxTimeLedToLose,
|
||||||
int initialStep, int flags, const char *board,
|
int initialStep, int flags, const char *board,
|
||||||
int nPiecesInHand_1, int nPiecesInHand_2, int nPiecesNeedRemove)
|
int nPiecesInHand_1, int nPiecesInHand_2, int nPiecesNeedRemove, uint64_t hash)
|
||||||
{
|
{
|
||||||
// 有效性判断
|
// 有效性判断
|
||||||
if (maxStepsLedToDraw < 0 || maxTimeLedToLose < 0 || initialStep < 0 ||
|
if (maxStepsLedToDraw < 0 || maxTimeLedToLose < 0 || initialStep < 0 ||
|
||||||
|
@ -320,24 +343,39 @@ bool NineChess::setContext(const struct Rule *rule, int maxStepsLedToDraw, int m
|
||||||
this->currentStep = initialStep;
|
this->currentStep = initialStep;
|
||||||
|
|
||||||
// 局面阶段标识
|
// 局面阶段标识
|
||||||
if (flags & GAME_NOTSTARTED)
|
if (flags & GAME_NOTSTARTED) {
|
||||||
context.stage = GAME_NOTSTARTED;
|
context.stage = GAME_NOTSTARTED;
|
||||||
else if (flags & GAME_PLACING)
|
}
|
||||||
|
else if (flags & GAME_PLACING) {
|
||||||
context.stage = GAME_PLACING;
|
context.stage = GAME_PLACING;
|
||||||
else if (flags & GAME_MOVING)
|
}
|
||||||
|
else if (flags & GAME_MOVING) {
|
||||||
context.stage = GAME_MOVING;
|
context.stage = GAME_MOVING;
|
||||||
else if (flags & GAME_OVER)
|
//context.hash ^= // TODO
|
||||||
|
}
|
||||||
|
else if (flags & GAME_OVER) {
|
||||||
context.stage = GAME_OVER;
|
context.stage = GAME_OVER;
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// 轮流状态标识
|
// 轮流状态标识
|
||||||
if (flags & PLAYER1)
|
if (flags & PLAYER1) {
|
||||||
|
// if (context.turn == PLAYER2) {
|
||||||
|
// context.hash ^= player2sTurnHash;
|
||||||
|
// }
|
||||||
context.turn = PLAYER1;
|
context.turn = PLAYER1;
|
||||||
else if (flags & PLAYER2)
|
}
|
||||||
|
else if (flags & PLAYER2) {
|
||||||
|
// if (context.turn == PLAYER1) {
|
||||||
|
// context.hash ^= player2sTurnHash;
|
||||||
|
// }
|
||||||
context.turn = PLAYER2;
|
context.turn = PLAYER2;
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// 动作状态标识
|
// 动作状态标识
|
||||||
if (flags & ACTION_CHOOSE)
|
if (flags & ACTION_CHOOSE)
|
||||||
|
@ -352,19 +390,37 @@ bool NineChess::setContext(const struct Rule *rule, int maxStepsLedToDraw, int m
|
||||||
// 当前棋局(3×8)
|
// 当前棋局(3×8)
|
||||||
if (board == nullptr) {
|
if (board == nullptr) {
|
||||||
memset(context.board, 0, sizeof(context.board));
|
memset(context.board, 0, sizeof(context.board));
|
||||||
|
context.hash = 0;
|
||||||
} else {
|
} else {
|
||||||
memcpy(context.board, board, sizeof(context.board));
|
memcpy(context.board, board, sizeof(context.board));
|
||||||
|
context.hash = hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算盘面子数
|
// 计算盘面子数
|
||||||
|
// 棋局,抽象为一个(5×8)的数组,上下两行留空
|
||||||
|
/*
|
||||||
|
0x00 代表无棋子
|
||||||
|
0x0F 代表禁点
|
||||||
|
0x11~0x1C 代表先手第 1~12 子
|
||||||
|
0x21~0x2C 代表后手第 1~12 子
|
||||||
|
判断棋子是先手的用 (board[i] & 0x10)
|
||||||
|
判断棋子是后手的用 (board[i] & 0x20)
|
||||||
|
*/
|
||||||
context.nPiecesOnBoard_1 = context.nPiecesOnBoard_2 = 0;
|
context.nPiecesOnBoard_1 = context.nPiecesOnBoard_2 = 0;
|
||||||
for (int r = 1; r < N_RINGS + 2; r++) {
|
for (int r = 1; r < N_RINGS + 2; r++) {
|
||||||
for (int s = 0; s < N_SEATS; s++) {
|
for (int s = 0; s < N_SEATS; s++) {
|
||||||
if (context.board[r * N_SEATS + s] & '\x10')
|
int pos = r * N_SEATS + s;
|
||||||
|
if (context.board[pos] & '\x10') {
|
||||||
context.nPiecesOnBoard_1++;
|
context.nPiecesOnBoard_1++;
|
||||||
else if (context.board[r * N_SEATS + s] & '\x20') {
|
}
|
||||||
|
else if (context.board[pos] & '\x20') {
|
||||||
context.nPiecesOnBoard_2++;
|
context.nPiecesOnBoard_2++;
|
||||||
}
|
}
|
||||||
|
else if (context.board[pos] & '\x0F') {
|
||||||
|
// 不计算盘面子数
|
||||||
|
}
|
||||||
|
|
||||||
|
//updateHash(pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -434,7 +490,8 @@ bool NineChess::setContext(const struct Rule *rule, int maxStepsLedToDraw, int m
|
||||||
}
|
}
|
||||||
|
|
||||||
void NineChess::getContext(struct Rule &rule, int &step, int &flags,
|
void NineChess::getContext(struct Rule &rule, int &step, int &flags,
|
||||||
int *&board, int &nPiecesInHand_1, int &nPiecesInHand_2, int &num_NeedRemove)
|
int *&board, int &nPiecesInHand_1, int &nPiecesInHand_2, int &num_NeedRemove,
|
||||||
|
uint64_t &hash)
|
||||||
{
|
{
|
||||||
rule = this->currentRule;
|
rule = this->currentRule;
|
||||||
step = this->currentStep;
|
step = this->currentStep;
|
||||||
|
@ -443,6 +500,7 @@ void NineChess::getContext(struct Rule &rule, int &step, int &flags,
|
||||||
nPiecesInHand_1 = context.nPiecesInHand_1;
|
nPiecesInHand_1 = context.nPiecesInHand_1;
|
||||||
nPiecesInHand_2 = context.nPiecesInHand_2;
|
nPiecesInHand_2 = context.nPiecesInHand_2;
|
||||||
num_NeedRemove = context.nPiecesNeedRemove;
|
num_NeedRemove = context.nPiecesNeedRemove;
|
||||||
|
hash = context.hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NineChess::reset()
|
bool NineChess::reset()
|
||||||
|
@ -486,6 +544,9 @@ bool NineChess::reset()
|
||||||
// 用时置零
|
// 用时置零
|
||||||
elapsedMS_1 = elapsedMS_2 = 0;
|
elapsedMS_1 = elapsedMS_2 = 0;
|
||||||
|
|
||||||
|
// 哈希归零
|
||||||
|
context.hash = 0;
|
||||||
|
|
||||||
// 提示
|
// 提示
|
||||||
setTips();
|
setTips();
|
||||||
|
|
||||||
|
@ -548,7 +609,7 @@ bool NineChess::getPieceCP(const Player &player, const int &number, int &c, int
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (int i = N_SEATS; i < N_SEATS * (N_RINGS + 1); i++) {
|
for (int i = POS_BEGIN; i < POS_END; i++) {
|
||||||
if (board_[i] == piece) {
|
if (board_[i] == piece) {
|
||||||
pos2cp(i, c, p);
|
pos2cp(i, c, p);
|
||||||
return true;
|
return true;
|
||||||
|
@ -578,7 +639,7 @@ bool NineChess::getCurrentPiece(Player &player, int &number)
|
||||||
|
|
||||||
bool NineChess::pos2cp(const int pos, int &c, int &p)
|
bool NineChess::pos2cp(const int pos, int &c, int &p)
|
||||||
{
|
{
|
||||||
if (pos < N_SEATS || pos >= N_SEATS * (N_RINGS + 1))
|
if (pos < POS_BEGIN || POS_END <= pos)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
c = pos / N_SEATS;
|
c = pos / N_SEATS;
|
||||||
|
@ -609,9 +670,10 @@ bool NineChess::place(int c, int p, long time_p /* = -1*/)
|
||||||
if (context.action != ACTION_PLACE)
|
if (context.action != ACTION_PLACE)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// 如果落子位置在棋盘外、已有子点或禁点,返回false
|
// 转换为 pos
|
||||||
int pos = cp2pos(c, p);
|
int pos = cp2pos(c, p);
|
||||||
|
|
||||||
|
// 如果落子位置在棋盘外、已有子点或禁点,返回false
|
||||||
if (!onBoard[pos] || board_[pos])
|
if (!onBoard[pos] || board_[pos])
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -637,6 +699,7 @@ bool NineChess::place(int c, int p, long time_p /* = -1*/)
|
||||||
}
|
}
|
||||||
|
|
||||||
board_[pos] = piece;
|
board_[pos] = piece;
|
||||||
|
updateHash(pos);
|
||||||
move_ = pos;
|
move_ = pos;
|
||||||
player_ms = update(time_p);
|
player_ms = update(time_p);
|
||||||
sprintf(cmdline, "(%1u,%1u) %02u:%02u.%03u",
|
sprintf(cmdline, "(%1u,%1u) %02u:%02u.%03u",
|
||||||
|
@ -725,7 +788,9 @@ bool NineChess::place(int c, int p, long time_p /* = -1*/)
|
||||||
c, p, player_ms / 60000, (player_ms % 60000) / 1000, player_ms % 1000);
|
c, p, player_ms / 60000, (player_ms % 60000) / 1000, player_ms % 1000);
|
||||||
cmdlist.push_back(string(cmdline));
|
cmdlist.push_back(string(cmdline));
|
||||||
board_[pos] = board_[currentPos];
|
board_[pos] = board_[currentPos];
|
||||||
|
updateHash(pos);
|
||||||
board_[currentPos] = '\x00';
|
board_[currentPos] = '\x00';
|
||||||
|
updateHash(currentPos);
|
||||||
currentPos = pos;
|
currentPos = pos;
|
||||||
currentStep++;
|
currentStep++;
|
||||||
n = addMills(currentPos);
|
n = addMills(currentPos);
|
||||||
|
@ -811,6 +876,7 @@ bool NineChess::capture(int c, int p, long time_p /* = -1*/)
|
||||||
currentPos = 0;
|
currentPos = 0;
|
||||||
context.nPiecesNeedRemove--;
|
context.nPiecesNeedRemove--;
|
||||||
currentStep++;
|
currentStep++;
|
||||||
|
updateHash(pos);
|
||||||
// 去子完成
|
// 去子完成
|
||||||
|
|
||||||
// 如果决出胜负
|
// 如果决出胜负
|
||||||
|
@ -937,6 +1003,7 @@ bool NineChess::place(int pos)
|
||||||
// 如非“落子”状态,返回false
|
// 如非“落子”状态,返回false
|
||||||
if (context.action != ACTION_PLACE)
|
if (context.action != ACTION_PLACE)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// 如果落子位置在棋盘外、已有子点或禁点,返回false
|
// 如果落子位置在棋盘外、已有子点或禁点,返回false
|
||||||
if (!onBoard[pos] || board_[pos])
|
if (!onBoard[pos] || board_[pos])
|
||||||
return false;
|
return false;
|
||||||
|
@ -959,6 +1026,7 @@ bool NineChess::place(int pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
board_[pos] = piece;
|
board_[pos] = piece;
|
||||||
|
updateHash(pos);
|
||||||
move_ = pos;
|
move_ = pos;
|
||||||
currentPos = pos;
|
currentPos = pos;
|
||||||
//step++;
|
//step++;
|
||||||
|
@ -1034,7 +1102,9 @@ bool NineChess::place(int pos)
|
||||||
// 移子
|
// 移子
|
||||||
move_ = (currentPos << 8) + pos;
|
move_ = (currentPos << 8) + pos;
|
||||||
board_[pos] = board_[currentPos];
|
board_[pos] = board_[currentPos];
|
||||||
|
updateHash(pos);
|
||||||
board_[currentPos] = '\x00';
|
board_[currentPos] = '\x00';
|
||||||
|
updateHash(currentPos);
|
||||||
currentPos = pos;
|
currentPos = pos;
|
||||||
//step++;
|
//step++;
|
||||||
n = addMills(currentPos);
|
n = addMills(currentPos);
|
||||||
|
@ -1111,6 +1181,7 @@ bool NineChess::capture(int pos)
|
||||||
move_ = -pos;
|
move_ = -pos;
|
||||||
currentPos = 0;
|
currentPos = 0;
|
||||||
context.nPiecesNeedRemove--;
|
context.nPiecesNeedRemove--;
|
||||||
|
updateHash(pos);
|
||||||
//step++;
|
//step++;
|
||||||
// 去子完成
|
// 去子完成
|
||||||
|
|
||||||
|
@ -1215,36 +1286,47 @@ bool NineChess::choose(int pos)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t NineChess::getHash()
|
||||||
|
{
|
||||||
|
return context.hash;
|
||||||
|
}
|
||||||
|
|
||||||
// hash函数,对应可重复去子的规则
|
// hash函数,对应可重复去子的规则
|
||||||
uint64_t NineChess::chessHash()
|
uint64_t NineChess::updateHash(int pos)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* hash各数据位详解(名为hash,但实际并无冲突,是算法用到的棋局数据的完全表示)
|
* hash各数据位详解(名为hash,但实际并无冲突,是算法用到的棋局数据的完全表示)
|
||||||
* 57-64位:空白不用,全为0
|
* 56-63位:空白不用,全为0
|
||||||
* 56位:轮流标识,0为先手,1为后手
|
* 55位:轮流标识,0为先手,1为后手
|
||||||
* 55位:动作标识,落子(选子移动)为0,1为去子
|
* 54位:动作标识,落子(选子移动)为0,1为去子
|
||||||
* 7-54位(共48位):从棋盘第一个位置点到最后一个位置点的棋子,每个点用2个二进制位表示,共24个位置点,即48位。
|
* 6-53位(共48位):从棋盘第一个位置点到最后一个位置点的棋子,每个点用2个二进制位表示,共24个位置点,即48位。
|
||||||
* 0b00表示空白,0b01表示先手棋子,0b10表示后手棋子,0b11表示禁点
|
* 0b00表示空白,0b01表示先手棋子,0b10表示后手棋子,0b11表示禁点
|
||||||
* 5-6位(共2位):待去子数,最大为3,用2个二进制位表示即可
|
* 4-5位(共2位):待去子数,最大为3,用2个二进制位表示即可
|
||||||
* 1-4位:player1的手棋数,不需要player2的(可计算出)
|
* 0-3位:player1的手棋数,不需要player2的(可计算出)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#if 0
|
||||||
uint64_t hash = 0ull;
|
uint64_t hash = 0ull;
|
||||||
|
|
||||||
for (int i = POS_BEGIN; i < POS_END; i++) {
|
for (int i = POS_BEGIN; i < POS_END; i++) {
|
||||||
hash |= board_[i] & 0x30;
|
hash |= board_[i] & 0x30;
|
||||||
hash <<= 2;
|
hash <<= 2;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint64_t temp = board_[pos] & 0x30 >> 4;
|
||||||
|
context.hash |= (temp) << ((pos - 8) * 2 + 6);
|
||||||
|
|
||||||
if (context.turn == PLAYER2)
|
if (context.turn == PLAYER2)
|
||||||
hash |= 1ull << 55;
|
context.hash |= 1ull << 55;
|
||||||
|
|
||||||
if (context.action == ACTION_CAPTURE)
|
if (context.action == ACTION_CAPTURE)
|
||||||
hash |= 1ull << 54;
|
context.hash |= 1ull << 54;
|
||||||
|
|
||||||
hash |= (uint64_t)context.nPiecesNeedRemove << 4;
|
context.hash |= (uint64_t)context.nPiecesNeedRemove << 4;
|
||||||
hash |= context.nPiecesInHand_1;
|
context.hash |= context.nPiecesInHand_1;
|
||||||
|
|
||||||
return hash;
|
return context.hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NineChess::giveup(Player loser)
|
bool NineChess::giveup(Player loser)
|
||||||
|
@ -1673,10 +1755,15 @@ bool NineChess::isAllSurrounded(enum Player ply)
|
||||||
|
|
||||||
void NineChess::cleanForbiddenPoints()
|
void NineChess::cleanForbiddenPoints()
|
||||||
{
|
{
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
for (int i = 1; i <= N_RINGS; i++) {
|
for (int i = 1; i <= N_RINGS; i++) {
|
||||||
for (int j = 0; j < N_SEATS; j++) {
|
for (int j = 0; j < N_SEATS; j++) {
|
||||||
if (board_[i * N_SEATS + j] == '\x0f')
|
pos = i * N_SEATS + j;
|
||||||
board_[i * N_SEATS + j] = '\x00';
|
if (board_[pos] == '\x0f') {
|
||||||
|
board_[pos] = '\x00';
|
||||||
|
updateHash(pos);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1774,7 +1861,9 @@ void NineChess::mirror(bool cmdChange /*= true*/)
|
||||||
for (j = 1; j < N_SEATS / 2; j++) {
|
for (j = 1; j < N_SEATS / 2; j++) {
|
||||||
ch = board_[i * N_SEATS + j];
|
ch = board_[i * N_SEATS + j];
|
||||||
board_[i * N_SEATS + j] = board_[(i + 1) * N_SEATS - j];
|
board_[i * N_SEATS + j] = board_[(i + 1) * N_SEATS - j];
|
||||||
|
//updateHash(i * N_SEATS + j);
|
||||||
board_[(i + 1) * N_SEATS - j] = ch;
|
board_[(i + 1) * N_SEATS - j] = ch;
|
||||||
|
//updateHash((i + 1) * N_SEATS - j);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1891,7 +1980,9 @@ void NineChess::turn(bool cmdChange /*= true*/)
|
||||||
for (i = 0; i < N_SEATS; i++) {
|
for (i = 0; i < N_SEATS; i++) {
|
||||||
ch = board_[N_SEATS + i];
|
ch = board_[N_SEATS + i];
|
||||||
board_[N_SEATS + i] = board_[N_SEATS * N_RINGS + i];
|
board_[N_SEATS + i] = board_[N_SEATS * N_RINGS + i];
|
||||||
|
//updateHash(N_SEATS + i);
|
||||||
board_[N_SEATS * N_RINGS + i] = ch;
|
board_[N_SEATS * N_RINGS + i] = ch;
|
||||||
|
//updateHash(N_SEATS * N_RINGS + i);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t llp1, llp2, llp3;
|
uint64_t llp1, llp2, llp3;
|
||||||
|
@ -2080,9 +2171,12 @@ void NineChess::rotate(int degrees, bool cmdChange /*= true*/)
|
||||||
ch2 = board_[i * N_SEATS + 1];
|
ch2 = board_[i * N_SEATS + 1];
|
||||||
for (j = 0; j < N_SEATS - 2; j++) {
|
for (j = 0; j < N_SEATS - 2; j++) {
|
||||||
board_[i * N_SEATS + j] = board_[i * N_SEATS + j + 2];
|
board_[i * N_SEATS + j] = board_[i * N_SEATS + j + 2];
|
||||||
|
//updateHash(i * N_SEATS + j);
|
||||||
}
|
}
|
||||||
board_[i * N_SEATS + 6] = ch1;
|
board_[i * N_SEATS + 6] = ch1;
|
||||||
|
//updateHash(i * N_SEATS + 6);
|
||||||
board_[i * N_SEATS + 7] = ch2;
|
board_[i * N_SEATS + 7] = ch2;
|
||||||
|
//updateHash(i * N_SEATS + 7);
|
||||||
}
|
}
|
||||||
} else if (degrees == 6) {
|
} else if (degrees == 6) {
|
||||||
for (i = 1; i <= N_RINGS; i++) {
|
for (i = 1; i <= N_RINGS; i++) {
|
||||||
|
@ -2090,16 +2184,21 @@ void NineChess::rotate(int degrees, bool cmdChange /*= true*/)
|
||||||
ch2 = board_[i * N_SEATS + 6];
|
ch2 = board_[i * N_SEATS + 6];
|
||||||
for (j = N_SEATS - 1; j >= 2; j--) {
|
for (j = N_SEATS - 1; j >= 2; j--) {
|
||||||
board_[i * N_SEATS + j] = board_[i * N_SEATS + j - 2];
|
board_[i * N_SEATS + j] = board_[i * N_SEATS + j - 2];
|
||||||
|
//updateHash(i * N_SEATS + j);
|
||||||
}
|
}
|
||||||
board_[i * N_SEATS + 1] = ch1;
|
board_[i * N_SEATS + 1] = ch1;
|
||||||
|
//updateHash(i * N_SEATS + 1);
|
||||||
board_[i * N_SEATS] = ch2;
|
board_[i * N_SEATS] = ch2;
|
||||||
|
//updateHash(i * N_SEATS);
|
||||||
}
|
}
|
||||||
} else if (degrees == 4) {
|
} else if (degrees == 4) {
|
||||||
for (i = 1; i <= N_RINGS; i++) {
|
for (i = 1; i <= N_RINGS; i++) {
|
||||||
for (j = 0; j < N_SEATS / 2; j++) {
|
for (j = 0; j < N_SEATS / 2; j++) {
|
||||||
ch1 = board_[i * N_SEATS + j];
|
ch1 = board_[i * N_SEATS + j];
|
||||||
board_[i * N_SEATS + j] = board_[i * N_SEATS + j + 4];
|
board_[i * N_SEATS + j] = board_[i * N_SEATS + j + 4];
|
||||||
|
//updateHash(i * N_SEATS + j);
|
||||||
board_[i * N_SEATS + j + 4] = ch1;
|
board_[i * N_SEATS + j + 4] = ch1;
|
||||||
|
//updateHash(i * N_SEATS + j + 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
|
|
|
@ -36,6 +36,9 @@ public:
|
||||||
// 横直斜3个方向,禁止修改!
|
// 横直斜3个方向,禁止修改!
|
||||||
static const int N_DIRECTIONS = 3;
|
static const int N_DIRECTIONS = 3;
|
||||||
|
|
||||||
|
// 棋盘点的个数:40
|
||||||
|
static const int N_POINTS = (NineChess::N_RINGS + 2) * NineChess::N_SEATS;
|
||||||
|
|
||||||
// 移动方向,包括顺时针、逆时针、向内、向外4个方向
|
// 移动方向,包括顺时针、逆时针、向内、向外4个方向
|
||||||
enum MoveDirection
|
enum MoveDirection
|
||||||
{
|
{
|
||||||
|
@ -123,6 +126,14 @@ public:
|
||||||
GAME_OVER = 0x0008 // 结局
|
GAME_OVER = 0x0008 // 结局
|
||||||
};
|
};
|
||||||
|
|
||||||
|
uint64_t rand64(void) {
|
||||||
|
return rand() ^
|
||||||
|
((uint64_t)rand() << 15) ^
|
||||||
|
((uint64_t)rand() << 30) ^
|
||||||
|
((uint64_t)rand() << 45) ^
|
||||||
|
((uint64_t)rand() << 60);
|
||||||
|
}
|
||||||
|
|
||||||
// 玩家标识, 轮流状态, 胜负标识
|
// 玩家标识, 轮流状态, 胜负标识
|
||||||
enum Player : uint16_t
|
enum Player : uint16_t
|
||||||
{
|
{
|
||||||
|
@ -143,6 +154,16 @@ public:
|
||||||
ACTION_CAPTURE = 0x0400 // 提子
|
ACTION_CAPTURE = 0x0400 // 提子
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 棋盘点上棋子的类型
|
||||||
|
enum PointType : uint16_t
|
||||||
|
{
|
||||||
|
POINT_TYPE_EMPTY = 0, // 没有棋子
|
||||||
|
POINT_TYPE_PLAYER1 = 1, // 先手的子
|
||||||
|
POINT_TYPE_PLAYER2 = 2, // 后手的子
|
||||||
|
POINT_TYPE_FORBIDDEN = 3, // 禁点
|
||||||
|
POINT_TYPE_COUNT = 4
|
||||||
|
};
|
||||||
|
|
||||||
// 棋局结构体,算法相关,包含当前棋盘数据
|
// 棋局结构体,算法相关,包含当前棋盘数据
|
||||||
// 单独分离出来供AI判断局面用,生成置换表时使用
|
// 单独分离出来供AI判断局面用,生成置换表时使用
|
||||||
struct ChessContext
|
struct ChessContext
|
||||||
|
@ -156,7 +177,13 @@ public:
|
||||||
判断棋子是先手的用 (board[i] & 0x10)
|
判断棋子是先手的用 (board[i] & 0x10)
|
||||||
判断棋子是后手的用 (board[i] & 0x20)
|
判断棋子是后手的用 (board[i] & 0x20)
|
||||||
*/
|
*/
|
||||||
int board[(NineChess::N_RINGS + 2) * NineChess::N_SEATS];
|
int board[N_POINTS];
|
||||||
|
|
||||||
|
// 局面哈希值
|
||||||
|
uint64_t hash;
|
||||||
|
|
||||||
|
// Zobrist 数组
|
||||||
|
//uint64_t zobrist[N_POINTS][POINT_TYPE_COUNT];
|
||||||
|
|
||||||
// 局面阶段标识
|
// 局面阶段标识
|
||||||
enum NineChess::GameStage stage;
|
enum NineChess::GameStage stage;
|
||||||
|
@ -219,6 +246,9 @@ private:
|
||||||
// 生成成三表
|
// 生成成三表
|
||||||
void createMillTable();
|
void createMillTable();
|
||||||
|
|
||||||
|
// 创建哈希值
|
||||||
|
void constructHash();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit NineChess();
|
explicit NineChess();
|
||||||
virtual ~NineChess();
|
virtual ~NineChess();
|
||||||
|
@ -238,12 +268,14 @@ public:
|
||||||
const char *board = nullptr, // 默认空棋盘
|
const char *board = nullptr, // 默认空棋盘
|
||||||
int nPiecesInHand_1 = 12, // 玩家1剩余未放置子数
|
int nPiecesInHand_1 = 12, // 玩家1剩余未放置子数
|
||||||
int nPiecesInHand_2 = 12, // 玩家2剩余未放置子数
|
int nPiecesInHand_2 = 12, // 玩家2剩余未放置子数
|
||||||
int nPiecesNeedRemove = 0 // 尚待去除的子数
|
int nPiecesNeedRemove = 0, // 尚待去除的子数
|
||||||
|
uint64_t hash = 0ull // Hash 为0
|
||||||
);
|
);
|
||||||
|
|
||||||
// 获取棋局状态和棋盘上下文
|
// 获取棋局状态和棋盘上下文
|
||||||
void getContext(struct Rule &rule, int &step, int &flags, int *&board,
|
void getContext(struct Rule &rule, int &step, int &flags, int *&board,
|
||||||
int &nPiecesInHand_1, int &p2_nPiecesInHand_2InHand, int &nPiecesNeedRemove);
|
int &nPiecesInHand_1, int &p2_nPiecesInHand_2InHand, int &nPiecesNeedRemove,
|
||||||
|
uint64_t &hash);
|
||||||
|
|
||||||
// 获取当前规则
|
// 获取当前规则
|
||||||
const struct Rule *getRule() const
|
const struct Rule *getRule() const
|
||||||
|
@ -448,7 +480,8 @@ protected:
|
||||||
bool capture(int pos);
|
bool capture(int pos);
|
||||||
|
|
||||||
// hash函数
|
// hash函数
|
||||||
uint64_t chessHash();
|
uint64_t getHash();
|
||||||
|
uint64_t updateHash(int pos);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// 当前使用的规则
|
// 当前使用的规则
|
||||||
|
@ -457,9 +490,12 @@ private:
|
||||||
// 棋局上下文
|
// 棋局上下文
|
||||||
struct ChessContext context;
|
struct ChessContext context;
|
||||||
|
|
||||||
// 棋局数据中的棋盘数据,单独提出来
|
// 棋局上下文中的棋盘数据,单独提出来
|
||||||
int *board_;
|
int *board_;
|
||||||
|
|
||||||
|
// 棋局哈希值
|
||||||
|
// uint64_t hash;
|
||||||
|
|
||||||
// 选中的棋子在board中的位置
|
// 选中的棋子在board中的位置
|
||||||
int currentPos;
|
int currentPos;
|
||||||
|
|
||||||
|
|
|
@ -447,8 +447,8 @@ int NineChessAi_ab::changeDepth(int originalDepth)
|
||||||
//int depthTable[] = { 2, 11, 11, 11, 11, 10, 9, 8, 8, 8, 7, 7, 1 };
|
//int depthTable[] = { 2, 11, 11, 11, 11, 10, 9, 8, 8, 8, 7, 7, 1 };
|
||||||
int depthTable[] = { 2, 12, 12, 12, 12, 11, 10, 9, 9, 9, 8, 7, 1 };
|
int depthTable[] = { 2, 12, 12, 12, 12, 11, 10, 9, 9, 9, 8, 7, 1 };
|
||||||
#else
|
#else
|
||||||
//int depthTable[] = { 2, 12, 12, 12, 12, 11, 10, 9, 8, 8, 8, 7, 1 };
|
int depthTable[] = { 2, 12, 12, 12, 12, 11, 10, 9, 8, 8, 8, 7, 1 };
|
||||||
int depthTable[] = { 2, 12, 12, 12, 12, 11, 10, 9, 9, 9, 8, 7, 1 };
|
//int depthTable[] = { 2, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 1 };
|
||||||
#endif // DEAL_WITH_HORIZON_EFFECT
|
#endif // DEAL_WITH_HORIZON_EFFECT
|
||||||
newDepth = depthTable[chessTemp.getPiecesInHandCount_1()];
|
newDepth = depthTable[chessTemp.getPiecesInHandCount_1()];
|
||||||
#elif defined GAME_PLACING_FIXED_DEPTH
|
#elif defined GAME_PLACING_FIXED_DEPTH
|
||||||
|
@ -516,6 +516,7 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
|
||||||
// 初始化
|
// 初始化
|
||||||
node->isLeaf = false;
|
node->isLeaf = false;
|
||||||
node->isTimeout = false;
|
node->isTimeout = false;
|
||||||
|
node->isHash = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// 搜索到叶子节点(决胜局面)
|
// 搜索到叶子节点(决胜局面)
|
||||||
|
@ -557,7 +558,7 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
|
||||||
|
|
||||||
#ifdef HASH_MAP_ENABLE
|
#ifdef HASH_MAP_ENABLE
|
||||||
// 检索 hashmap
|
// 检索 hashmap
|
||||||
uint64_t hash = chessTemp.chessHash();
|
uint64_t hash = chessTemp.getHash();
|
||||||
node->hash = hash;
|
node->hash = hash;
|
||||||
|
|
||||||
hashMapMutex.lock();
|
hashMapMutex.lock();
|
||||||
|
@ -567,6 +568,11 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
|
||||||
if (node != rootNode &&
|
if (node != rootNode &&
|
||||||
iter != hashmap.end() &&
|
iter != hashmap.end() &&
|
||||||
iter->second.depth >= depth) {
|
iter->second.depth >= depth) {
|
||||||
|
#ifdef DEBUG_AB_TREE
|
||||||
|
node->isHash = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// TODO: 处理 Alpha/Beta 确切值
|
||||||
node->value = iter->second.value;
|
node->value = iter->second.value;
|
||||||
|
|
||||||
if (chessContext->turn == NineChess::PLAYER1)
|
if (chessContext->turn == NineChess::PLAYER1)
|
||||||
|
@ -791,6 +797,7 @@ const char *NineChessAi_ab::move2string(int move)
|
||||||
unordered_map<uint64_t, NineChessAi_ab::HashValue>::iterator NineChessAi_ab::findHash(uint64_t hash)
|
unordered_map<uint64_t, NineChessAi_ab::HashValue>::iterator NineChessAi_ab::findHash(uint64_t hash)
|
||||||
{
|
{
|
||||||
auto iter = hashmap.find(hash);
|
auto iter = hashmap.find(hash);
|
||||||
|
|
||||||
if (iter != hashmap.end())
|
if (iter != hashmap.end())
|
||||||
return iter;
|
return iter;
|
||||||
|
|
||||||
|
@ -805,7 +812,7 @@ unordered_map<uint64_t, NineChessAi_ab::HashValue>::iterator NineChessAi_ab::fin
|
||||||
chessTempShift.turn(false);
|
chessTempShift.turn(false);
|
||||||
for (int k = 0; k < 4; k++) {
|
for (int k = 0; k < 4; k++) {
|
||||||
chessTempShift.rotate(k * 90, false);
|
chessTempShift.rotate(k * 90, false);
|
||||||
iter = hashmap.find(chessTempShift.chessHash());
|
iter = hashmap.find(chessTempShift.getHash());
|
||||||
if (iter != hashmap.end())
|
if (iter != hashmap.end())
|
||||||
return iter;
|
return iter;
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,12 +48,13 @@ public:
|
||||||
#ifdef DEBUG_AB_TREE
|
#ifdef DEBUG_AB_TREE
|
||||||
string cmd;
|
string cmd;
|
||||||
enum NineChess::Player player; // 此招是谁下的
|
enum NineChess::Player player; // 此招是谁下的
|
||||||
int depth;
|
int depth; // 深度
|
||||||
bool evaluated; // 是否评估过局面
|
bool evaluated; // 是否评估过局面
|
||||||
int alpha; // 当前搜索结点走棋方搜索到的最好值,任何比它小的值对当前结点的走棋方都没有意义。当函数递归时 Alpha 和 Beta 不但取负数而且要交换位置
|
int alpha; // 当前搜索结点走棋方搜索到的最好值,任何比它小的值对当前结点的走棋方都没有意义。当函数递归时 Alpha 和 Beta 不但取负数而且要交换位置
|
||||||
int beta; // 表示对手目前的劣势,这是对手所能承受的最坏结果,Beta 值越大,表示对手劣势越明显,如果当前结点返回 Beta 或比 Beta 更好的值,作为父结点的对方就绝对不会选择这种策略
|
int beta; // 表示对手目前的劣势,这是对手所能承受的最坏结果,Beta 值越大,表示对手劣势越明显,如果当前结点返回 Beta 或比 Beta 更好的值,作为父结点的对方就绝对不会选择这种策略
|
||||||
bool isTimeout; // 是否遍历到此结点时因为超时而被迫退出
|
bool isTimeout; // 是否遍历到此结点时因为超时而被迫退出
|
||||||
bool isLeaf; // 是否为叶子结点, 叶子结点是决胜局面
|
bool isLeaf; // 是否为叶子结点, 叶子结点是决胜局面
|
||||||
|
bool isHash; // 是否从 Hash 读取
|
||||||
NineChess::GameStage stage; // 摆棋阶段还是走棋阶段
|
NineChess::GameStage stage; // 摆棋阶段还是走棋阶段
|
||||||
NineChess::Action action; // 动作状态
|
NineChess::Action action; // 动作状态
|
||||||
int nPiecesOnBoardDiff; // 场上棋子个数和对手的差值
|
int nPiecesOnBoardDiff; // 场上棋子个数和对手的差值
|
||||||
|
|
Loading…
Reference in New Issue