NineChess模型类重构前的最后一次提交,Windows和Linux下都能正确编译。
下一步为AI做准备,改模型为位棋盘形式。
This commit is contained in:
parent
022ae41475
commit
2e9a690df3
|
@ -318,3 +318,7 @@ CMakeLists.txt.user*
|
|||
|
||||
# visual studio code
|
||||
.vscode/
|
||||
|
||||
# markdown temp files
|
||||
*.md.Html
|
||||
*.md.Htm
|
||||
|
|
|
@ -15,6 +15,8 @@ TEMPLATE = app
|
|||
CONFIG += C++11 \
|
||||
warn_off
|
||||
|
||||
INCLUDEPATH += src
|
||||
|
||||
SOURCES += \
|
||||
src/main.cpp \
|
||||
src/boarditem.cpp \
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE QtCreatorProject>
|
||||
<!-- Written by QtCreator 4.6.1, 2018-11-29T03:34:51. -->
|
||||
<!-- Written by QtCreator 4.6.1, 2018-11-30T23:59:04. -->
|
||||
<qtcreator>
|
||||
<data>
|
||||
<variable>EnvironmentId</variable>
|
||||
|
@ -292,7 +292,7 @@
|
|||
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.ProFile">ninechess.pro</value>
|
||||
<value type="bool" key="Qt4ProjectManager.Qt4RunConfiguration.UseDyldImageSuffix">false</value>
|
||||
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory"></value>
|
||||
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory.default"></value>
|
||||
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory.default">E:/My program/QT/NineChess/build-ninechess-Desktop_Qt_5_11_0_MSVC2017_64bit-Debug</value>
|
||||
<value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
|
|
|
@ -130,44 +130,44 @@ bool NineChess::setData(const struct Rule *rule, int s, int t, int step, int fla
|
|||
this->rule.maxSteps = s;
|
||||
this->rule.maxTime = t;
|
||||
// 设置步数
|
||||
data_.step = step;
|
||||
this->step = step;
|
||||
|
||||
// 设置状态
|
||||
|
||||
// 局面阶段标识
|
||||
if (flags & GAME_NOTSTARTED)
|
||||
data_.phase = GAME_NOTSTARTED;
|
||||
phase = GAME_NOTSTARTED;
|
||||
else if (flags & GAME_OPENING)
|
||||
data_.phase = GAME_OPENING;
|
||||
phase = GAME_OPENING;
|
||||
else if (flags & GAME_MID)
|
||||
data_.phase = GAME_MID;
|
||||
phase = GAME_MID;
|
||||
else if (flags & GAME_OVER)
|
||||
data_.phase = GAME_OVER;
|
||||
phase = GAME_OVER;
|
||||
else
|
||||
return false;
|
||||
// 轮流状态标识
|
||||
if (flags & PLAYER1)
|
||||
data_.turn = PLAYER1;
|
||||
turn = PLAYER1;
|
||||
else if (flags & PLAYER2)
|
||||
data_.turn = PLAYER2;
|
||||
turn = PLAYER2;
|
||||
else
|
||||
return false;
|
||||
// 动作状态标识
|
||||
if (flags & ACTION_CHOOSE)
|
||||
data_.action = ACTION_CHOOSE;
|
||||
action = ACTION_CHOOSE;
|
||||
else if (flags & ACTION_PLACE)
|
||||
data_.action = ACTION_PLACE;
|
||||
action = ACTION_PLACE;
|
||||
else if (flags & ACTION_REMOVE)
|
||||
data_.action = ACTION_REMOVE;
|
||||
action = ACTION_REMOVE;
|
||||
else
|
||||
return false;
|
||||
// 胜负标识
|
||||
data_.winner = NOBODY;
|
||||
winner = NOBODY;
|
||||
// 当前棋局(3×8)
|
||||
if (boardsource == nullptr)
|
||||
memset(data_.board, 0, sizeof(data_.board));
|
||||
memset(this->board, 0, sizeof(this->board));
|
||||
else
|
||||
memcpy(data_.board, boardsource, sizeof(data_.board));
|
||||
memcpy(this->board, boardsource, sizeof(this->board));
|
||||
// 生成招法表
|
||||
for (int i = 1; i <= RING; i++)
|
||||
{
|
||||
|
@ -257,38 +257,38 @@ bool NineChess::setData(const struct Rule *rule, int s, int t, int step, int fla
|
|||
}
|
||||
|
||||
// 计算盘面子数
|
||||
data_.player1_Remain = data_.player2_Remain = 0;
|
||||
player1_Remain = player2_Remain = 0;
|
||||
for (int i = 1; i < RING + 2; i++)
|
||||
{
|
||||
for (int j = 0; j < SEAT; j++)
|
||||
{
|
||||
if (data_.board[i*SEAT + j] & '\x10')
|
||||
data_.player1_Remain++;
|
||||
else if (data_.board[i*SEAT + j] & '\x20') {
|
||||
data_.player2_Remain++;
|
||||
if (board[i*SEAT + j] & '\x10')
|
||||
player1_Remain++;
|
||||
else if (board[i*SEAT + j] & '\x20') {
|
||||
player2_Remain++;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 设置玩家盘面剩余子数和未放置子数
|
||||
if (data_.player1_Remain > rule->numOfChess || data_.player2_Remain > rule->numOfChess)
|
||||
if (player1_Remain > rule->numOfChess || player2_Remain > rule->numOfChess)
|
||||
return false;
|
||||
if (p1_InHand < 0 || p2_InHand < 0)
|
||||
return false;
|
||||
data_.player1_InHand = rule->numOfChess - data_.player1_Remain;
|
||||
data_.player2_InHand = rule->numOfChess - data_.player2_Remain;
|
||||
data_.player1_InHand = p1_InHand < data_.player1_InHand ? p1_InHand : data_.player1_InHand;
|
||||
data_.player2_InHand = p2_InHand < data_.player2_InHand ? p2_InHand : data_.player2_InHand;
|
||||
player1_InHand = rule->numOfChess - player1_Remain;
|
||||
player2_InHand = rule->numOfChess - player2_Remain;
|
||||
player1_InHand = p1_InHand < player1_InHand ? p1_InHand : player1_InHand;
|
||||
player2_InHand = p2_InHand < player2_InHand ? p2_InHand : player2_InHand;
|
||||
|
||||
// 设置去子状态时的剩余尚待去除子数
|
||||
if (flags & ACTION_REMOVE) {
|
||||
if (num_NeedRemove >= 0 && num_NeedRemove < 3)
|
||||
data_.num_NeedRemove = num_NeedRemove;
|
||||
this->num_NeedRemove = num_NeedRemove;
|
||||
}
|
||||
else
|
||||
data_.num_NeedRemove = 0;
|
||||
this->num_NeedRemove = 0;
|
||||
|
||||
// 清空成三记录
|
||||
data_.millList.clear();
|
||||
millList.clear();
|
||||
|
||||
// 不选中棋子
|
||||
currentPos = 0;
|
||||
|
@ -322,53 +322,53 @@ void NineChess::getData(struct Rule &rule, int &step, int &chess, const char *&b
|
|||
int &p1_InHand, int &p2_InHand, int &num_NeedRemove)
|
||||
{
|
||||
rule = this->rule;
|
||||
step = data_.step;
|
||||
chess = data_.phase | data_.turn | data_.action | data_.winner;
|
||||
board = data_.board;
|
||||
p1_InHand = data_.player1_InHand;
|
||||
p2_InHand = data_.player2_InHand;
|
||||
num_NeedRemove = data_.num_NeedRemove;
|
||||
step = this->step;
|
||||
chess = phase | turn | action | winner;
|
||||
board = this->board;
|
||||
p1_InHand = player1_InHand;
|
||||
p2_InHand = player2_InHand;
|
||||
num_NeedRemove = this->num_NeedRemove;
|
||||
}
|
||||
|
||||
const char * NineChess::getBoard()
|
||||
{
|
||||
return data_.board;
|
||||
return board;
|
||||
}
|
||||
|
||||
bool NineChess::reset()
|
||||
{
|
||||
if (data_.phase == GAME_NOTSTARTED && player1_MS == player2_MS == 0)
|
||||
if (phase == GAME_NOTSTARTED && player1_MS == player2_MS == 0)
|
||||
return true;
|
||||
|
||||
// 步数归零
|
||||
data_.step = 0;
|
||||
step = 0;
|
||||
|
||||
// 局面阶段标识
|
||||
data_.phase = GAME_NOTSTARTED;
|
||||
phase = GAME_NOTSTARTED;
|
||||
|
||||
// 轮流状态标识
|
||||
data_.turn = PLAYER1;
|
||||
turn = PLAYER1;
|
||||
|
||||
// 动作状态标识
|
||||
data_.action = ACTION_PLACE;
|
||||
action = ACTION_PLACE;
|
||||
|
||||
// 胜负标识
|
||||
data_.winner = NOBODY;
|
||||
winner = NOBODY;
|
||||
|
||||
// 当前棋局(3×8)
|
||||
memset(data_.board, 0, sizeof(data_.board));
|
||||
memset(board, 0, sizeof(board));
|
||||
|
||||
// 盘面子数归零
|
||||
data_.player1_Remain = data_.player2_Remain = 0;
|
||||
player1_Remain = player2_Remain = 0;
|
||||
|
||||
// 设置玩家盘面剩余子数和未放置子数
|
||||
data_.player1_InHand = data_.player2_InHand = rule.numOfChess;
|
||||
player1_InHand = player2_InHand = rule.numOfChess;
|
||||
|
||||
// 设置去子状态时的剩余尚待去除子数
|
||||
data_.num_NeedRemove = 0;
|
||||
num_NeedRemove = 0;
|
||||
|
||||
// 清空成三记录
|
||||
data_.millList.clear();
|
||||
millList.clear();
|
||||
|
||||
// 不选中棋子
|
||||
currentPos = 0;
|
||||
|
@ -401,16 +401,16 @@ bool NineChess::reset()
|
|||
bool NineChess::start()
|
||||
{
|
||||
// 如果游戏已经开始,则返回false
|
||||
if (data_.phase == GAME_OPENING || data_.phase == GAME_MID)
|
||||
if (phase == GAME_OPENING || phase == GAME_MID)
|
||||
return false;
|
||||
|
||||
// 如果游戏结束,则重置游戏,进入未开始状态
|
||||
if (data_.phase == GAME_OVER)
|
||||
if (phase == GAME_OVER)
|
||||
reset();
|
||||
|
||||
// 如果游戏处于未开始状态
|
||||
if (data_.phase == GAME_NOTSTARTED) {
|
||||
data_.phase = GAME_OPENING;
|
||||
if (phase == GAME_NOTSTARTED) {
|
||||
phase = GAME_OPENING;
|
||||
// 启动计时器
|
||||
ftime(&startTimeb);
|
||||
}
|
||||
|
@ -429,18 +429,18 @@ int NineChess::cp2pos(int c, int p)
|
|||
bool NineChess::place(int c, int p, long time_p /* = -1*/)
|
||||
{
|
||||
// 如果局面为“结局”,返回false
|
||||
if (data_.phase == GAME_OVER)
|
||||
if (phase == GAME_OVER)
|
||||
return false;
|
||||
// 如果局面为“未开局”,则开具
|
||||
if (data_.phase == GAME_NOTSTARTED)
|
||||
if (phase == GAME_NOTSTARTED)
|
||||
start();
|
||||
|
||||
// 如非“落子”状态,返回false
|
||||
if (data_.action != ACTION_PLACE)
|
||||
if (action != ACTION_PLACE)
|
||||
return false;
|
||||
// 如果落子位置在棋盘外、已有子点或禁点,返回false
|
||||
int pos = cp2pos(c, p);
|
||||
if (!inBoard[pos] || data_.board[pos])
|
||||
if (!inBoard[pos] || board[pos])
|
||||
return false;
|
||||
// 时间的临时变量
|
||||
long player_ms = -1;
|
||||
|
@ -448,29 +448,28 @@ bool NineChess::place(int c, int p, long time_p /* = -1*/)
|
|||
// 对于开局落子
|
||||
char piece = '\x00';
|
||||
int n = 0;
|
||||
if (data_.phase == GAME_OPENING) {
|
||||
if (phase == GAME_OPENING) {
|
||||
// 先手下
|
||||
if (data_.turn == PLAYER1)
|
||||
if (turn == PLAYER1)
|
||||
{
|
||||
piece = '\x11' + rule.numOfChess - data_.player1_InHand;
|
||||
data_.board[pos] = piece;
|
||||
data_.player1_InHand--;
|
||||
data_.player1_Remain++;
|
||||
piece = '\x11' + rule.numOfChess - player1_InHand;
|
||||
board[pos] = piece;
|
||||
player1_InHand--;
|
||||
player1_Remain++;
|
||||
}
|
||||
// 后手下
|
||||
else
|
||||
{
|
||||
piece = '\x21' + rule.numOfChess - data_.player2_InHand;
|
||||
data_.board[pos] = piece;
|
||||
data_.player2_InHand--;
|
||||
data_.player2_Remain++;
|
||||
piece = '\x21' + rule.numOfChess - player2_InHand;
|
||||
board[pos] = piece;
|
||||
player2_InHand--;
|
||||
player2_Remain++;
|
||||
}
|
||||
player_ms = update(time_p);
|
||||
data_.move_ = pos;
|
||||
sprintf(cmdline, "(%1u,%1u) %02u:%02u.%03u", c, p, player_ms / 60000, player_ms / 1000, player_ms % 1000);
|
||||
cmdlist.push_back(string(cmdline));
|
||||
currentPos = pos;
|
||||
data_.step++;
|
||||
step++;
|
||||
// 如果决出胜负
|
||||
if (win()) {
|
||||
setTip();
|
||||
|
@ -481,19 +480,19 @@ bool NineChess::place(int c, int p, long time_p /* = -1*/)
|
|||
// 开局阶段未成三
|
||||
if (n == 0) {
|
||||
// 如果双方都无未放置的棋子
|
||||
if (data_.player1_InHand == 0 && data_.player2_InHand == 0) {
|
||||
if (player1_InHand == 0 && player2_InHand == 0) {
|
||||
// 进入中局阶段
|
||||
data_.phase = GAME_MID;
|
||||
phase = GAME_MID;
|
||||
// 进入选子状态
|
||||
data_.action = ACTION_CHOOSE;
|
||||
action = ACTION_CHOOSE;
|
||||
// 清除禁点
|
||||
cleanForbidden();
|
||||
// 设置轮到谁走
|
||||
if (rule.isDefensiveMoveFirst) {
|
||||
data_.turn = PLAYER2;
|
||||
turn = PLAYER2;
|
||||
}
|
||||
else {
|
||||
data_.turn = PLAYER1;
|
||||
turn = PLAYER1;
|
||||
}
|
||||
// 再决胜负
|
||||
if (win()) {
|
||||
|
@ -510,19 +509,19 @@ bool NineChess::place(int c, int p, long time_p /* = -1*/)
|
|||
// 如果成三
|
||||
else {
|
||||
// 设置去子数目
|
||||
data_.num_NeedRemove = rule.removeMore ? n : 1;
|
||||
num_NeedRemove = rule.removeMore ? n : 1;
|
||||
// 进入去子状态
|
||||
data_.action = ACTION_REMOVE;
|
||||
action = ACTION_REMOVE;
|
||||
}
|
||||
setTip();
|
||||
return true;
|
||||
}
|
||||
|
||||
// 对于中局落子
|
||||
else if (data_.phase == GAME_MID) {
|
||||
else if (phase == GAME_MID) {
|
||||
// 如果落子不合法
|
||||
if ((data_.turn == PLAYER1 && (data_.player1_Remain > rule.numAtLest || !rule.canFly)) ||
|
||||
(data_.turn == PLAYER2 && (data_.player2_Remain > rule.numAtLest || !rule.canFly))) {
|
||||
if ((turn == PLAYER1 && (player1_Remain > rule.numAtLest || !rule.canFly)) ||
|
||||
(turn == PLAYER2 && (player2_Remain > rule.numAtLest || !rule.canFly))) {
|
||||
int i;
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (pos == moveTable[currentPos][i])
|
||||
|
@ -534,20 +533,19 @@ bool NineChess::place(int c, int p, long time_p /* = -1*/)
|
|||
}
|
||||
// 移子
|
||||
player_ms = update(time_p);
|
||||
data_.move_ = (currentPos << 8) | pos;
|
||||
sprintf(cmdline, "(%1u,%1u)->(%1u,%1u) %02u:%02u.%03u", currentPos / SEAT, currentPos % SEAT + 1,
|
||||
c, p, player_ms / 60000, player_ms / 1000, player_ms % 1000);
|
||||
cmdlist.push_back(string(cmdline));
|
||||
data_.board[pos] = data_.board[currentPos];
|
||||
data_.board[currentPos] = '\x00';
|
||||
board[pos] = board[currentPos];
|
||||
board[currentPos] = '\x00';
|
||||
currentPos = pos;
|
||||
data_.step++;
|
||||
step++;
|
||||
n = addMills(currentPos);
|
||||
|
||||
// 中局阶段未成三
|
||||
if (n == 0) {
|
||||
// 进入选子状态
|
||||
data_.action = ACTION_CHOOSE;
|
||||
action = ACTION_CHOOSE;
|
||||
// 设置轮到谁走
|
||||
changeTurn();
|
||||
// 如果决出胜负
|
||||
|
@ -559,9 +557,9 @@ bool NineChess::place(int c, int p, long time_p /* = -1*/)
|
|||
// 中局阶段成三
|
||||
else {
|
||||
// 设置去子数目
|
||||
data_.num_NeedRemove = rule.removeMore ? n : 1;
|
||||
num_NeedRemove = rule.removeMore ? n : 1;
|
||||
// 进入去子状态
|
||||
data_.action = ACTION_REMOVE;
|
||||
action = ACTION_REMOVE;
|
||||
setTip();
|
||||
}
|
||||
setTip();
|
||||
|
@ -574,20 +572,20 @@ bool NineChess::place(int c, int p, long time_p /* = -1*/)
|
|||
bool NineChess::remove(int c, int p, long time_p /* = -1*/)
|
||||
{
|
||||
// 如果局面为"未开局"或“结局”,返回false
|
||||
if (data_.phase == GAME_NOTSTARTED || data_.phase == GAME_OVER)
|
||||
if (phase == GAME_NOTSTARTED || phase == GAME_OVER)
|
||||
return false;
|
||||
// 如非“去子”状态,返回false
|
||||
if (data_.action != ACTION_REMOVE)
|
||||
if (action != ACTION_REMOVE)
|
||||
return false;
|
||||
// 如果去子完成,返回false
|
||||
if (data_.num_NeedRemove <= 0)
|
||||
if (num_NeedRemove <= 0)
|
||||
return false;
|
||||
// 时间的临时变量
|
||||
long player_ms = -1;
|
||||
int pos = cp2pos(c, p);
|
||||
// 对手
|
||||
enum Player opponent = PLAYER2;
|
||||
if (data_.turn == PLAYER2)
|
||||
if (turn == PLAYER2)
|
||||
opponent = PLAYER1;
|
||||
// 判断去子不是对手棋
|
||||
if (getWhosPiece(c, p) != opponent)
|
||||
|
@ -599,21 +597,20 @@ bool NineChess::remove(int c, int p, long time_p /* = -1*/)
|
|||
}
|
||||
|
||||
// 去子(设置禁点)
|
||||
if (rule.hasForbidden && data_.phase == GAME_OPENING)
|
||||
data_.board[pos] = '\x0f';
|
||||
if (rule.hasForbidden && phase == GAME_OPENING)
|
||||
board[pos] = '\x0f';
|
||||
else // 去子
|
||||
data_.board[pos] = '\x00';
|
||||
if (data_.turn == PLAYER1)
|
||||
data_.player2_Remain--;
|
||||
else if (data_.turn == PLAYER2)
|
||||
data_.player1_Remain--;
|
||||
board[pos] = '\x00';
|
||||
if (turn == PLAYER1)
|
||||
player2_Remain--;
|
||||
else if (turn == PLAYER2)
|
||||
player1_Remain--;
|
||||
player_ms = update(time_p);
|
||||
data_.move_ = 0xFF00 | pos;
|
||||
sprintf(cmdline, "-(%1u,%1u) %02u:%02u.%03u", c, p, player_ms / 60000, player_ms / 1000, player_ms % 1000);
|
||||
cmdlist.push_back(string(cmdline));
|
||||
currentPos = 0;
|
||||
data_.num_NeedRemove--;
|
||||
data_.step++;
|
||||
num_NeedRemove--;
|
||||
step++;
|
||||
// 去子完成
|
||||
|
||||
// 如果决出胜负
|
||||
|
@ -622,28 +619,28 @@ bool NineChess::remove(int c, int p, long time_p /* = -1*/)
|
|||
return true;
|
||||
}
|
||||
// 还有其余的子要去吗
|
||||
if (data_.num_NeedRemove > 0) {
|
||||
if (num_NeedRemove > 0) {
|
||||
// 继续去子
|
||||
return true;
|
||||
}
|
||||
// 所有去子都完成了
|
||||
else {
|
||||
// 开局阶段
|
||||
if (data_.phase == GAME_OPENING) {
|
||||
if (phase == GAME_OPENING) {
|
||||
// 如果双方都无未放置的棋子
|
||||
if (data_.player1_InHand == 0 && data_.player2_InHand == 0) {
|
||||
if (player1_InHand == 0 && player2_InHand == 0) {
|
||||
// 进入中局阶段
|
||||
data_.phase = GAME_MID;
|
||||
phase = GAME_MID;
|
||||
// 进入选子状态
|
||||
data_.action = ACTION_CHOOSE;
|
||||
action = ACTION_CHOOSE;
|
||||
// 清除禁点
|
||||
cleanForbidden();
|
||||
// 设置轮到谁走
|
||||
if (rule.isDefensiveMoveFirst) {
|
||||
data_.turn = PLAYER2;
|
||||
turn = PLAYER2;
|
||||
}
|
||||
else {
|
||||
data_.turn = PLAYER1;
|
||||
turn = PLAYER1;
|
||||
}
|
||||
// 再决胜负
|
||||
if (win()) {
|
||||
|
@ -654,7 +651,7 @@ bool NineChess::remove(int c, int p, long time_p /* = -1*/)
|
|||
// 如果双方还有子
|
||||
else {
|
||||
// 进入落子状态
|
||||
data_.action = ACTION_PLACE;
|
||||
action = ACTION_PLACE;
|
||||
// 设置轮到谁走
|
||||
changeTurn();
|
||||
// 如果决出胜负
|
||||
|
@ -667,7 +664,7 @@ bool NineChess::remove(int c, int p, long time_p /* = -1*/)
|
|||
// 中局阶段
|
||||
else {
|
||||
// 进入选子状态
|
||||
data_.action = ACTION_CHOOSE;
|
||||
action = ACTION_CHOOSE;
|
||||
// 设置轮到谁走
|
||||
changeTurn();
|
||||
// 如果决出胜负
|
||||
|
@ -684,20 +681,20 @@ bool NineChess::remove(int c, int p, long time_p /* = -1*/)
|
|||
bool NineChess::choose(int c, int p)
|
||||
{
|
||||
// 如果局面不是"中局”,返回false
|
||||
if (data_.phase != GAME_MID)
|
||||
if (phase != GAME_MID)
|
||||
return false;
|
||||
// 如非“选子”或“落子”状态,返回false
|
||||
if (data_.action != ACTION_CHOOSE && data_.action != ACTION_PLACE)
|
||||
if (action != ACTION_CHOOSE && action != ACTION_PLACE)
|
||||
return false;
|
||||
int pos = cp2pos(c, p);
|
||||
// 根据先后手,判断可选子
|
||||
char t ='\0';
|
||||
if (data_.turn == PLAYER1)
|
||||
if (turn == PLAYER1)
|
||||
t = '\x10';
|
||||
else if (data_.turn == PLAYER2)
|
||||
else if (turn == PLAYER2)
|
||||
t = '\x20';
|
||||
// 判断选子是否可选
|
||||
if (data_.board[pos] & t) {
|
||||
if (board[pos] & t) {
|
||||
// 判断pos处的棋子是否被“闷”
|
||||
if (isSurrounded(pos)) {
|
||||
return false;
|
||||
|
@ -705,7 +702,7 @@ bool NineChess::choose(int c, int p)
|
|||
// 选子
|
||||
currentPos = pos;
|
||||
// 选子完成,进入落子状态
|
||||
data_.action = ACTION_PLACE;
|
||||
action = ACTION_PLACE;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -713,12 +710,12 @@ bool NineChess::choose(int c, int p)
|
|||
|
||||
bool NineChess::giveup(Player loser)
|
||||
{
|
||||
if (data_.phase == GAME_MID || data_.phase == GAME_OPENING)
|
||||
if (phase == GAME_MID || phase == GAME_OPENING)
|
||||
{
|
||||
if (loser == PLAYER1)
|
||||
{
|
||||
data_.phase = GAME_OVER;
|
||||
data_.winner = PLAYER2;
|
||||
phase = GAME_OVER;
|
||||
winner = PLAYER2;
|
||||
tip = "玩家1投子认负,恭喜玩家2获胜!";
|
||||
sprintf(cmdline, "Player1 give up!");
|
||||
cmdlist.push_back(string(cmdline));
|
||||
|
@ -726,8 +723,8 @@ bool NineChess::giveup(Player loser)
|
|||
}
|
||||
else if (loser == PLAYER2)
|
||||
{
|
||||
data_.phase = GAME_OVER;
|
||||
data_.winner = PLAYER1;
|
||||
phase = GAME_OVER;
|
||||
winner = PLAYER1;
|
||||
tip = "玩家2投子认负,恭喜玩家1获胜!";
|
||||
sprintf(cmdline, "Player2 give up!");
|
||||
cmdlist.push_back(string(cmdline));
|
||||
|
@ -804,11 +801,11 @@ bool NineChess::command(const char *cmd)
|
|||
inline long NineChess::update(long time_p /*= -1*/)
|
||||
{
|
||||
long ret = -1;
|
||||
long *player_ms = (data_.turn == PLAYER1 ? &(player1_MS) : &(player2_MS));
|
||||
long playerNext_ms = (data_.turn == PLAYER1 ? player2_MS : player1_MS);
|
||||
long *player_ms = (turn == PLAYER1 ? &player1_MS : &player2_MS);
|
||||
long playerNext_ms = (turn == PLAYER1 ? player2_MS : player1_MS);
|
||||
|
||||
// 根据局面调整计时器
|
||||
switch (data_.phase)
|
||||
switch (phase)
|
||||
{
|
||||
case NineChess::GAME_OPENING:
|
||||
case NineChess::GAME_MID:
|
||||
|
@ -850,9 +847,9 @@ inline long NineChess::update(long time_p /*= -1*/)
|
|||
// 是否分出胜负
|
||||
bool NineChess::win()
|
||||
{
|
||||
if (data_.phase == GAME_OVER)
|
||||
if (phase == GAME_OVER)
|
||||
return true;
|
||||
if (data_.phase == GAME_NOTSTARTED)
|
||||
if (phase == GAME_NOTSTARTED)
|
||||
return false;
|
||||
|
||||
// 如果有时间限定
|
||||
|
@ -861,8 +858,8 @@ bool NineChess::win()
|
|||
// 如果玩家1超时
|
||||
if (player1_MS > rule.maxTime * 60000) {
|
||||
player1_MS = rule.maxTime * 60000;
|
||||
data_.winner = PLAYER2;
|
||||
data_.phase = GAME_OVER;
|
||||
winner = PLAYER2;
|
||||
phase = GAME_OVER;
|
||||
tip = "玩家1超时,恭喜玩家2获胜!";
|
||||
sprintf(cmdline, "Time over. Player2 win!");
|
||||
cmdlist.push_back(string(cmdline));
|
||||
|
@ -871,8 +868,8 @@ bool NineChess::win()
|
|||
// 如果玩家2超时
|
||||
else if (player2_MS > rule.maxTime * 60000) {
|
||||
player2_MS = rule.maxTime * 60000;
|
||||
data_.winner = PLAYER1;
|
||||
data_.phase = GAME_OVER;
|
||||
winner = PLAYER1;
|
||||
phase = GAME_OVER;
|
||||
tip = "玩家2超时,恭喜玩家1获胜!";
|
||||
sprintf(cmdline, "Time over. Player1 win!");
|
||||
cmdlist.push_back(string(cmdline));
|
||||
|
@ -882,9 +879,9 @@ bool NineChess::win()
|
|||
|
||||
// 如果有步数限定
|
||||
if (rule.maxSteps > 0) {
|
||||
if (data_.step > rule.maxSteps) {
|
||||
data_.winner = DRAW;
|
||||
data_.phase = GAME_OVER;
|
||||
if (step > rule.maxSteps) {
|
||||
winner = DRAW;
|
||||
phase = GAME_OVER;
|
||||
sprintf(cmdline, "Steps over. In draw!");
|
||||
cmdlist.push_back(string(cmdline));
|
||||
return true;
|
||||
|
@ -892,48 +889,48 @@ bool NineChess::win()
|
|||
}
|
||||
|
||||
// 如果玩家1子数小于赛点,则玩家2获胜
|
||||
if (data_.player1_Remain + data_.player1_InHand < rule.numAtLest) {
|
||||
data_.winner = PLAYER2;
|
||||
data_.phase = GAME_OVER;
|
||||
if (player1_Remain + player1_InHand < rule.numAtLest) {
|
||||
winner = PLAYER2;
|
||||
phase = GAME_OVER;
|
||||
sprintf(cmdline, "Player2 win!");
|
||||
cmdlist.push_back(string(cmdline));
|
||||
return true;
|
||||
}
|
||||
// 如果玩家2子数小于赛点,则玩家1获胜
|
||||
else if (data_.player2_Remain + data_.player2_InHand < rule.numAtLest) {
|
||||
data_.winner = PLAYER1;
|
||||
data_.phase = GAME_OVER;
|
||||
else if (player2_Remain + player2_InHand < rule.numAtLest) {
|
||||
winner = PLAYER1;
|
||||
phase = GAME_OVER;
|
||||
sprintf(cmdline, "Player1 win!");
|
||||
cmdlist.push_back(string(cmdline));
|
||||
return true;
|
||||
}
|
||||
// 如果摆满了,根据规则判断胜负
|
||||
else if (data_.player1_Remain + data_.player2_Remain >= SEAT * RING) {
|
||||
else if (player1_Remain + player2_Remain >= SEAT * RING) {
|
||||
if (rule.isFullLose) {
|
||||
data_.winner = PLAYER2;
|
||||
data_.phase = GAME_OVER;
|
||||
winner = PLAYER2;
|
||||
phase = GAME_OVER;
|
||||
sprintf(cmdline, "Player2 win!");
|
||||
cmdlist.push_back(string(cmdline));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
data_.winner = DRAW;
|
||||
data_.phase = GAME_OVER;
|
||||
winner = DRAW;
|
||||
phase = GAME_OVER;
|
||||
sprintf(cmdline, "Full. In draw!");
|
||||
cmdlist.push_back(string(cmdline));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// 如果中局被“闷”
|
||||
else if (data_.phase == GAME_MID && data_.action == ACTION_CHOOSE && isAllSurrounded(data_.turn)) {
|
||||
else if (phase == GAME_MID && action == ACTION_CHOOSE && isAllSurrounded(turn)) {
|
||||
// 规则要求被“闷”判负,则对手获胜
|
||||
if (rule.isNoWayLose) {
|
||||
if (data_.turn == PLAYER1)
|
||||
if (turn == PLAYER1)
|
||||
{
|
||||
tip = "玩家1无子可走,恭喜玩家2获胜!";
|
||||
data_.winner = PLAYER2;
|
||||
data_.phase = GAME_OVER;
|
||||
winner = PLAYER2;
|
||||
phase = GAME_OVER;
|
||||
sprintf(cmdline, "Player1 no way to go. Player2 win!");
|
||||
cmdlist.push_back(string(cmdline));
|
||||
return true;
|
||||
|
@ -941,8 +938,8 @@ bool NineChess::win()
|
|||
else
|
||||
{
|
||||
tip = "玩家2无子可走,恭喜玩家1获胜!";
|
||||
data_.winner = PLAYER1;
|
||||
data_.phase = GAME_OVER;
|
||||
winner = PLAYER1;
|
||||
phase = GAME_OVER;
|
||||
sprintf(cmdline, "Player2 no way to go. Player1 win!");
|
||||
cmdlist.push_back(string(cmdline));
|
||||
return true;
|
||||
|
@ -963,12 +960,12 @@ int NineChess::isInMills(int pos)
|
|||
{
|
||||
int n = 0;
|
||||
int pos1, pos2;
|
||||
char m = data_.board[pos] & '\x30';
|
||||
char m = board[pos] & '\x30';
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
pos1 = millTable[pos][i][0];
|
||||
pos2 = millTable[pos][i][1];
|
||||
if (m & data_.board[pos1] & data_.board[pos2])
|
||||
if (m & board[pos1] & board[pos2])
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
|
@ -983,14 +980,14 @@ int NineChess::addMills(int pos)
|
|||
long long mill = 0;
|
||||
int n = 0;
|
||||
int p[3], min, temp;
|
||||
char m = data_.board[pos] & '\x30';
|
||||
char m = board[pos] & '\x30';
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
p[0] = pos;
|
||||
p[1] = millTable[pos][i][0];
|
||||
p[2] = millTable[pos][i][1];
|
||||
// 如果成三
|
||||
if (m & data_.board[p[1]] & data_.board[p[2]]) {
|
||||
if (m & board[p[1]] & board[p[2]]) {
|
||||
// 排序
|
||||
for (int j = 0; j < 2; j++) {
|
||||
min = j;
|
||||
|
@ -1005,11 +1002,11 @@ int NineChess::addMills(int pos)
|
|||
}
|
||||
}
|
||||
// 成三
|
||||
mill = (((long long)(data_.board[p[0]])) << 40)
|
||||
mill = (((long long)board[p[0]]) << 40)
|
||||
+ (((long long)p[0]) << 32)
|
||||
+ (((long long)(data_.board[p[1]])) << 24)
|
||||
+ (((long long)board[p[1]]) << 24)
|
||||
+ (((long long)p[1]) << 16)
|
||||
+ (((long long)(data_.board[p[2]])) << 8)
|
||||
+ (((long long)board[p[2]]) << 8)
|
||||
+ (long long)p[2];
|
||||
|
||||
// 如果允许相同三连反复去子
|
||||
|
@ -1022,15 +1019,15 @@ int NineChess::addMills(int pos)
|
|||
// 迭代器
|
||||
list<long long>::iterator itor;
|
||||
// 遍历
|
||||
for (itor = data_.millList.begin(); itor != data_.millList.end(); itor++)
|
||||
for (itor = millList.begin(); itor != millList.end(); itor++)
|
||||
{
|
||||
if (mill == *itor)
|
||||
break;
|
||||
}
|
||||
// 如果没找到历史项
|
||||
if (itor == data_.millList.end()) {
|
||||
if (itor == millList.end()) {
|
||||
n++;
|
||||
data_.millList.push_back(mill);
|
||||
millList.push_back(mill);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1050,7 +1047,7 @@ bool NineChess::isAllInMills(enum Player player)
|
|||
|
||||
for (int i = 1; i <= RING; i++)
|
||||
for (int j = 0; j < SEAT; j++) {
|
||||
if (data_.board[i*SEAT + j] & ch) {
|
||||
if (board[i*SEAT + j] & ch) {
|
||||
if (!isInMills(i*SEAT + j)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1063,13 +1060,13 @@ bool NineChess::isAllInMills(enum Player player)
|
|||
bool NineChess::isSurrounded(int pos)
|
||||
{
|
||||
// 判断pos处的棋子是否被“闷”
|
||||
if ((data_.turn == PLAYER1 && (data_.player1_Remain > rule.numAtLest || !rule.canFly)) ||
|
||||
(data_.turn == PLAYER2 && (data_.player2_Remain > rule.numAtLest || !rule.canFly)))
|
||||
if ((turn == PLAYER1 && (player1_Remain > rule.numAtLest || !rule.canFly)) ||
|
||||
(turn == PLAYER2 && (player2_Remain > rule.numAtLest || !rule.canFly)))
|
||||
{
|
||||
int i, movePos;
|
||||
for (i = 0; i < 4; i++) {
|
||||
movePos = moveTable[pos][i];
|
||||
if (movePos && !data_.board[movePos])
|
||||
if (movePos && !board[movePos])
|
||||
break;
|
||||
}
|
||||
// 被围住
|
||||
|
@ -1089,11 +1086,11 @@ bool NineChess::isAllSurrounded(enum Player ply)
|
|||
else if (ply == PLAYER2)
|
||||
t &= '\x20';
|
||||
// 如果摆满
|
||||
if (data_.player1_Remain + data_.player2_Remain >= SEAT * RING)
|
||||
if (player1_Remain + player2_Remain >= SEAT * RING)
|
||||
return true;
|
||||
// 判断是否可以飞子
|
||||
if ((data_.turn == PLAYER1 && (data_.player1_Remain <= rule.numAtLest && rule.canFly)) ||
|
||||
(data_.turn == PLAYER2 && (data_.player2_Remain <= rule.numAtLest && rule.canFly)))
|
||||
if ((turn == PLAYER1 && (player1_Remain <= rule.numAtLest && rule.canFly)) ||
|
||||
(turn == PLAYER2 && (player2_Remain <= rule.numAtLest && rule.canFly)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -1103,10 +1100,10 @@ bool NineChess::isAllSurrounded(enum Player ply)
|
|||
for (int j = 0; j < SEAT; j++)
|
||||
{
|
||||
int movePos;
|
||||
if (t & data_.board[i*SEAT + j]) {
|
||||
if (t & board[i*SEAT + j]) {
|
||||
for (int k = 0; k < 4; k++) {
|
||||
movePos = moveTable[i*SEAT + j][k];
|
||||
if (movePos && !data_.board[movePos])
|
||||
if (movePos && !board[movePos])
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1119,70 +1116,70 @@ void NineChess::cleanForbidden()
|
|||
{
|
||||
for (int i = 1; i <= RING; i++)
|
||||
for (int j = 0; j < SEAT; j++) {
|
||||
if (data_.board[i*SEAT + j] == '\x0f')
|
||||
data_.board[i*SEAT + j] = '\x00';
|
||||
if (board[i*SEAT + j] == '\x0f')
|
||||
board[i*SEAT + j] = '\x00';
|
||||
}
|
||||
}
|
||||
|
||||
enum NineChess::Player NineChess::changeTurn()
|
||||
{
|
||||
// 设置轮到谁走
|
||||
return data_.turn = (data_.turn == PLAYER1) ? PLAYER2 : PLAYER1;
|
||||
return turn = (turn == PLAYER1) ? PLAYER2 : PLAYER1;
|
||||
}
|
||||
|
||||
void NineChess::setTip()
|
||||
{
|
||||
switch (data_.phase)
|
||||
switch (phase)
|
||||
{
|
||||
case NineChess::GAME_NOTSTARTED:
|
||||
tip = "轮到玩家1落子,剩余" + std::to_string(data_.player1_InHand) + "子";
|
||||
tip = "轮到玩家1落子,剩余" + std::to_string(player1_InHand) + "子";
|
||||
break;
|
||||
case NineChess::GAME_OPENING:
|
||||
if (data_.action == ACTION_PLACE) {
|
||||
if (data_.turn == PLAYER1) {
|
||||
tip = "轮到玩家1落子,剩余" + std::to_string(data_.player1_InHand) + "子";
|
||||
if (action == ACTION_PLACE) {
|
||||
if (turn == PLAYER1) {
|
||||
tip = "轮到玩家1落子,剩余" + std::to_string(player1_InHand) + "子";
|
||||
}
|
||||
else if (data_.turn == PLAYER2) {
|
||||
tip = "轮到玩家2落子,剩余" + std::to_string(data_.player2_InHand) + "子";
|
||||
else if (turn == PLAYER2) {
|
||||
tip = "轮到玩家2落子,剩余" + std::to_string(player2_InHand) + "子";
|
||||
}
|
||||
}
|
||||
else if (data_.action == ACTION_REMOVE) {
|
||||
if (data_.turn == PLAYER1) {
|
||||
tip = "轮到玩家1去子,需去" + std::to_string(data_.num_NeedRemove) + "子";
|
||||
else if (action == ACTION_REMOVE) {
|
||||
if (turn == PLAYER1) {
|
||||
tip = "轮到玩家1去子,需去" + std::to_string(num_NeedRemove) + "子";
|
||||
}
|
||||
else if (data_.turn == PLAYER2) {
|
||||
tip = "轮到玩家2去子,需去" + std::to_string(data_.num_NeedRemove) + "子";
|
||||
else if (turn == PLAYER2) {
|
||||
tip = "轮到玩家2去子,需去" + std::to_string(num_NeedRemove) + "子";
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NineChess::GAME_MID:
|
||||
if (data_.action == ACTION_PLACE || data_.action == ACTION_CHOOSE) {
|
||||
if (data_.turn == PLAYER1) {
|
||||
if (action == ACTION_PLACE || action == ACTION_CHOOSE) {
|
||||
if (turn == PLAYER1) {
|
||||
tip = "轮到玩家1选子移动";
|
||||
}
|
||||
else if (data_.turn == PLAYER2) {
|
||||
else if (turn == PLAYER2) {
|
||||
tip = "轮到玩家2选子移动";
|
||||
}
|
||||
}
|
||||
else if (data_.action == ACTION_REMOVE) {
|
||||
if (data_.turn == PLAYER1) {
|
||||
tip = "轮到玩家1去子,需去" + std::to_string(data_.num_NeedRemove) + "子";
|
||||
else if (action == ACTION_REMOVE) {
|
||||
if (turn == PLAYER1) {
|
||||
tip = "轮到玩家1去子,需去" + std::to_string(num_NeedRemove) + "子";
|
||||
}
|
||||
else if (data_.turn == PLAYER2) {
|
||||
tip = "轮到玩家2去子,需去" + std::to_string(data_.num_NeedRemove) + "子";
|
||||
else if (turn == PLAYER2) {
|
||||
tip = "轮到玩家2去子,需去" + std::to_string(num_NeedRemove) + "子";
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NineChess::GAME_OVER:
|
||||
if (data_.winner == DRAW)
|
||||
if (winner == DRAW)
|
||||
tip = "超出限定步数,双方平局";
|
||||
else if (data_.winner == PLAYER1) {
|
||||
else if (winner == PLAYER1) {
|
||||
if (tip.find("无子可走") != tip.npos)
|
||||
tip += "恭喜玩家1获胜!";
|
||||
else
|
||||
tip = "恭喜玩家1获胜!";
|
||||
}
|
||||
else if (data_.winner == PLAYER2) {
|
||||
else if (winner == PLAYER2) {
|
||||
if (tip.find("无子可走") != tip.npos)
|
||||
tip += "恭喜玩家2获胜!";
|
||||
else
|
||||
|
@ -1197,9 +1194,9 @@ void NineChess::setTip()
|
|||
enum NineChess::Player NineChess::getWhosPiece(int c, int p)
|
||||
{
|
||||
int pos = cp2pos(c, p);
|
||||
if (data_.board[pos] & '\x10')
|
||||
if (board[pos] & '\x10')
|
||||
return PLAYER1;
|
||||
else if (data_.board[pos] & '\x20')
|
||||
else if (board[pos] & '\x20')
|
||||
return PLAYER2;
|
||||
return NOBODY;
|
||||
}
|
||||
|
@ -1207,7 +1204,7 @@ enum NineChess::Player NineChess::getWhosPiece(int c, int p)
|
|||
int NineChess::getPieceNum(int c, int p)
|
||||
{
|
||||
int pos = cp2pos(c, p);
|
||||
int n = 0x0f & data_.board[pos];
|
||||
int n = 0x0f & board[pos];
|
||||
return n;
|
||||
}
|
||||
|
||||
|
|
|
@ -87,10 +87,125 @@ public:
|
|||
// 预定义的规则
|
||||
static const struct Rule RULES[RULENUM];
|
||||
|
||||
// 嵌套的数据结构体
|
||||
// 单独提出来,是为了ai计算的时候压栈的数据量少
|
||||
struct Data
|
||||
{
|
||||
private:
|
||||
// 空棋盘点位,用于判断一个棋子位置是否在棋盘上
|
||||
static const char inBoard[(RING + 2)*SEAT];
|
||||
|
||||
// 招法表,每个位置有最多4种走法:顺时针、逆时针、向内、向外
|
||||
// 这个表跟规则有关,一旦规则改变需要重新修改
|
||||
static char moveTable[(RING + 2)*SEAT][4];
|
||||
|
||||
// 成三表,表示棋盘上各个位置有成三关系的对应位置表
|
||||
// 这个表跟规则有关,一旦规则改变需要重新修改
|
||||
static char millTable[(RING + 2)*SEAT][3][2];
|
||||
|
||||
public:
|
||||
NineChess();
|
||||
virtual ~NineChess();
|
||||
/* 拷贝构造函数
|
||||
其实NineChess类没有指针类型的成员变量,list内的值也是深拷贝
|
||||
所以没有必要写拷贝构造函数了
|
||||
*/
|
||||
//explicit NineChess(const NineChess &);
|
||||
|
||||
// 设置棋局状态和棋盘数据,用于初始化
|
||||
bool setData(const struct Rule *rule,
|
||||
int s = 0, // 限制步数
|
||||
int t = 0, // 限制时间
|
||||
int step = 0, // 默认起始步数为0
|
||||
int flags = GAME_NOTSTARTED | PLAYER1 | ACTION_PLACE | NOBODY, // 默认状态
|
||||
const char *boardsource = nullptr, // 默认空棋盘
|
||||
int p1_InHand = 12, // 玩家1剩余未放置子数
|
||||
int p2_InHand = 12, // 玩家2剩余未放置子数
|
||||
int num_NeedRemove = 0 // 尚待去除的子数
|
||||
);
|
||||
|
||||
// 获取棋局状态和棋盘数据
|
||||
void getData(struct Rule &rule, int &step, int &flags, const char *&boardsource, int &p1_InHand, int &p2_InHand, int &num_NeedRemove);
|
||||
// 获取棋盘数据
|
||||
const char *getBoard();
|
||||
// 获取当前规则
|
||||
const struct Rule *getRule() { return &rule; }
|
||||
// 获取当前点
|
||||
int getCurrentPos() { return currentPos; }
|
||||
// 获取当前步数
|
||||
int getStep() { return step; }
|
||||
// 获取局面阶段标识
|
||||
enum Phases getPhase() { return phase; }
|
||||
// 获取轮流状态标识
|
||||
enum Player whosTurn() { return turn; }
|
||||
// 获取动作状态标识
|
||||
enum Actions getAction() { return action; }
|
||||
// 判断胜负
|
||||
enum Player whoWin() { return winner; }
|
||||
// 玩家1和玩家2的用时
|
||||
void getPlayer_TimeMS(int &p1_ms, int &p2_ms);
|
||||
// 获取棋局的字符提示
|
||||
const string getTip() { return tip; }
|
||||
// 获取位置点棋子的归属人
|
||||
enum Player getWhosPiece(int c, int p);
|
||||
// 获取位置点棋子的序号
|
||||
int getPieceNum(int c, int p);
|
||||
// 获取当前招法
|
||||
const char *getCmdLine() { return cmdline; }
|
||||
// 获得棋谱
|
||||
const list<string> * getCmdList() { return &cmdlist; }
|
||||
// 获取开局时间
|
||||
timeb getStartTimeb() { return startTimeb; }
|
||||
// 重新设置开局时间
|
||||
void setStartTimeb(timeb stimeb) { startTimeb = stimeb; }
|
||||
|
||||
// 玩家1剩余未放置子数
|
||||
int getPlayer1_InHand() { return player1_InHand; }
|
||||
// 玩家2剩余未放置子数
|
||||
int getPlayer2_InHand() { return player2_InHand; }
|
||||
// 玩家1盘面剩余子数
|
||||
int getPlayer1_Remain() { return player1_Remain; }
|
||||
// 玩家1盘面剩余子数
|
||||
int getPlayer2_Remain() { return player2_Remain; }
|
||||
// 尚待去除的子数
|
||||
int getNum_NeedRemove() { return num_NeedRemove; }
|
||||
|
||||
// 游戏重置
|
||||
bool reset();
|
||||
// 游戏开始
|
||||
bool start();
|
||||
// 选子,在第c圈第p个位置,为迎合日常,c和p下标都从1开始
|
||||
bool choose(int c, int p);
|
||||
// 落子,在第c圈第p个位置,为迎合日常,c和p下标都从1开始
|
||||
bool place(int c, int p, long time_p = -1);
|
||||
// 去子,在第c圈第p个位置,为迎合日常,c和p下标都从1开始
|
||||
bool remove(int c, int p, long time_p = -1);
|
||||
// 认输
|
||||
bool giveup(Player loser);
|
||||
// 命令行解析函数
|
||||
bool command(const char *cmd);
|
||||
|
||||
protected:
|
||||
// 判断棋盘pos处的棋子处于几个“三连”中
|
||||
int isInMills(int pos);
|
||||
// 判断玩家的所有棋子是否都处于“三连”状态
|
||||
bool isAllInMills(enum Player);
|
||||
// 判断玩家的棋子是否被围
|
||||
bool isSurrounded(int pos);
|
||||
// 判断玩家的棋子是否全部被围
|
||||
bool isAllSurrounded(enum Player);
|
||||
// 三连加入列表
|
||||
int addMills(int pos);
|
||||
// 将第c圈,第p位转化为棋盘下标形式,c和p下标都从1开始
|
||||
int cp2pos(int c, int p);
|
||||
// 更新时间和状态,用内联函数以提高效率
|
||||
inline long update(long time_p = -1);
|
||||
// 是否分出胜负
|
||||
bool win();
|
||||
// 清除所有禁点
|
||||
void cleanForbidden();
|
||||
// 改变轮流
|
||||
enum NineChess::Player changeTurn();
|
||||
// 设置提示
|
||||
void setTip();
|
||||
|
||||
private:
|
||||
// 当前步数
|
||||
int step;
|
||||
// 局面阶段标识
|
||||
|
@ -147,131 +262,9 @@ public:
|
|||
去子:0xFF??,??为棋盘上去子点的位置
|
||||
*/
|
||||
short move_;
|
||||
};
|
||||
|
||||
private:
|
||||
// 空棋盘点位,用于判断一个棋子位置是否在棋盘上
|
||||
static const char inBoard[(RING + 2)*SEAT];
|
||||
|
||||
// 招法表,每个位置有最多4种走法:顺时针、逆时针、向内、向外
|
||||
// 这个表跟规则有关,一旦规则改变需要重新修改
|
||||
static char moveTable[(RING + 2)*SEAT][4];
|
||||
|
||||
// 成三表,表示棋盘上各个位置有成三关系的对应位置表
|
||||
// 这个表跟规则有关,一旦规则改变需要重新修改
|
||||
static char millTable[(RING + 2)*SEAT][3][2];
|
||||
|
||||
public:
|
||||
NineChess();
|
||||
virtual ~NineChess();
|
||||
/* 拷贝构造函数
|
||||
其实NineChess类没有指针类型的成员变量,list内的值也是深拷贝
|
||||
所以没有必要写拷贝构造函数了
|
||||
*/
|
||||
//explicit NineChess(const NineChess &);
|
||||
|
||||
// 设置棋局状态和棋盘数据,用于初始化
|
||||
bool setData(const struct Rule *rule,
|
||||
int s = 0, // 限制步数
|
||||
int t = 0, // 限制时间
|
||||
int step = 0, // 默认起始步数为0
|
||||
int flags = GAME_NOTSTARTED | PLAYER1 | ACTION_PLACE | NOBODY, // 默认状态
|
||||
const char *boardsource = nullptr, // 默认空棋盘
|
||||
int p1_InHand = 12, // 玩家1剩余未放置子数
|
||||
int p2_InHand = 12, // 玩家2剩余未放置子数
|
||||
int num_NeedRemove = 0 // 尚待去除的子数
|
||||
);
|
||||
|
||||
// 获取棋局状态和棋盘数据
|
||||
void getData(struct Rule &rule, int &step, int &flags, const char *&boardsource, int &p1_InHand, int &p2_InHand, int &num_NeedRemove);
|
||||
// 获取棋盘数据
|
||||
const char *getBoard();
|
||||
// 获取当前规则
|
||||
const struct Rule *getRule() { return &rule; }
|
||||
// 获取当前点
|
||||
int getCurrentPos() { return currentPos; }
|
||||
// 获取当前步数
|
||||
int getStep() { return data_.step; }
|
||||
// 获取局面阶段标识
|
||||
enum Phases getPhase() { return data_.phase; }
|
||||
// 获取轮流状态标识
|
||||
enum Player whosTurn() { return data_.turn; }
|
||||
// 获取动作状态标识
|
||||
enum Actions getAction() { return data_.action; }
|
||||
// 判断胜负
|
||||
enum Player whoWin() { return data_.winner; }
|
||||
// 玩家1和玩家2的用时
|
||||
void getPlayer_TimeMS(int &p1_ms, int &p2_ms);
|
||||
// 获取棋局的字符提示
|
||||
const string getTip() { return tip; }
|
||||
// 获取位置点棋子的归属人
|
||||
enum Player getWhosPiece(int c, int p);
|
||||
// 获取位置点棋子的序号
|
||||
int getPieceNum(int c, int p);
|
||||
// 获取当前招法
|
||||
const char *getCmdLine() { return cmdline; }
|
||||
// 获得棋谱
|
||||
const list<string> * getCmdList() { return &cmdlist; }
|
||||
// 获取开局时间
|
||||
timeb getStartTimeb() { return startTimeb; }
|
||||
// 重新设置开局时间
|
||||
void setStartTimeb(timeb stimeb) { startTimeb = stimeb; }
|
||||
|
||||
// 玩家1剩余未放置子数
|
||||
int getPlayer1_InHand() { return data_.player1_InHand; }
|
||||
// 玩家2剩余未放置子数
|
||||
int getPlayer2_InHand() { return data_.player2_InHand; }
|
||||
// 玩家1盘面剩余子数
|
||||
int getPlayer1_Remain() { return data_.player1_Remain; }
|
||||
// 玩家1盘面剩余子数
|
||||
int getPlayer2_Remain() { return data_.player2_Remain; }
|
||||
// 尚待去除的子数
|
||||
int getNum_NeedRemove() { return data_.num_NeedRemove; }
|
||||
|
||||
// 游戏重置
|
||||
bool reset();
|
||||
// 游戏开始
|
||||
bool start();
|
||||
// 选子,在第c圈第p个位置,为迎合日常,c和p下标都从1开始
|
||||
bool choose(int c, int p);
|
||||
// 落子,在第c圈第p个位置,为迎合日常,c和p下标都从1开始
|
||||
bool place(int c, int p, long time_p = -1);
|
||||
// 去子,在第c圈第p个位置,为迎合日常,c和p下标都从1开始
|
||||
bool remove(int c, int p, long time_p = -1);
|
||||
// 认输
|
||||
bool giveup(Player loser);
|
||||
// 命令行解析函数
|
||||
bool command(const char *cmd);
|
||||
|
||||
protected:
|
||||
// 判断棋盘pos处的棋子处于几个“三连”中
|
||||
int isInMills(int pos);
|
||||
// 判断玩家的所有棋子是否都处于“三连”状态
|
||||
bool isAllInMills(enum Player);
|
||||
// 判断玩家的棋子是否被围
|
||||
bool isSurrounded(int pos);
|
||||
// 判断玩家的棋子是否全部被围
|
||||
bool isAllSurrounded(enum Player);
|
||||
// 三连加入列表
|
||||
int addMills(int pos);
|
||||
// 将第c圈,第p位转化为棋盘下标形式,c和p下标都从1开始
|
||||
int cp2pos(int c, int p);
|
||||
// 更新时间和状态,用内联函数以提高效率
|
||||
inline long update(long time_p = -1);
|
||||
// 是否分出胜负
|
||||
bool win();
|
||||
// 清除所有禁点
|
||||
void cleanForbidden();
|
||||
// 改变轮流
|
||||
enum NineChess::Player changeTurn();
|
||||
// 设置提示
|
||||
void setTip();
|
||||
|
||||
private:
|
||||
// 当前使用的规则
|
||||
struct Rule rule;
|
||||
// 棋盘数据
|
||||
struct Data data_;
|
||||
// 选中的棋子在board中的位置
|
||||
int currentPos;
|
||||
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
#include "NineChessAi_ab.h"
|
||||
#include "ninechessai_ab.h"
|
||||
#include <cmath>
|
||||
#include <time.h>
|
||||
|
||||
NineChessAi_ab::NineChessAi_ab():
|
||||
rootNode(nullptr),
|
||||
requiredQuit(false),
|
||||
depth(5) // 默认5层深度
|
||||
depth(3) // 默认3层深度
|
||||
{
|
||||
rootNode = new Node;
|
||||
rootNode->value = 0;
|
||||
rootNode->move_ = 0;
|
||||
rootNode->parent = nullptr;
|
||||
}
|
||||
|
||||
NineChessAi_ab::~NineChessAi_ab()
|
||||
|
@ -14,25 +20,30 @@ NineChessAi_ab::~NineChessAi_ab()
|
|||
|
||||
void NineChessAi_ab::buildChildren(Node *node)
|
||||
{
|
||||
// 列出所有合法的下一招
|
||||
;
|
||||
}
|
||||
|
||||
void NineChessAi_ab::sortChildren(Node *node)
|
||||
{
|
||||
// 这个函数对效率的影响很大,
|
||||
// 排序好的话,剪枝较早,节省时间
|
||||
// 但不能在此函数耗费太多时间
|
||||
;
|
||||
// 这个函数对效率的影响很大,排序好的话,剪枝较早,节省时间,但不能在此函数耗费太多时间
|
||||
// 先赋初值,初始值不会影响alpha-beta剪枝
|
||||
for (auto i : node->children) {
|
||||
i->value = evaluate(node);
|
||||
}
|
||||
// 排序
|
||||
node->children.sort([](Node *n1, Node *n2) { return n1->value > n2->value; });
|
||||
}
|
||||
|
||||
void NineChessAi_ab::deleteTree(Node *node)
|
||||
{
|
||||
if (rootNode) {
|
||||
for (auto i : rootNode->children) {
|
||||
// 递归删除节点树
|
||||
if (node) {
|
||||
for (auto i : node->children) {
|
||||
deleteTree(i);
|
||||
}
|
||||
rootNode->children.clear();
|
||||
delete rootNode;
|
||||
node->children.clear();
|
||||
delete node;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,63 +56,100 @@ void NineChessAi_ab::setChess(const NineChess &chess)
|
|||
|
||||
int NineChessAi_ab::evaluate(Node *node)
|
||||
{
|
||||
// 初始评估值为0,对先手有利则增大,对后手有利则减小
|
||||
// 初始评估值为0,对先手有利则增大,对后手有利则减小
|
||||
int value = 0;
|
||||
|
||||
|
||||
|
||||
|
||||
// 赋值返回
|
||||
// 赋值返回
|
||||
node->value = value;
|
||||
return value;
|
||||
}
|
||||
|
||||
int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
|
||||
{
|
||||
// 评价值
|
||||
// 评价值
|
||||
int value;
|
||||
if (!depth || !(node->children.size())) {
|
||||
node->value = evaluate(node);
|
||||
return node->value;
|
||||
}
|
||||
|
||||
// 生成子节点树
|
||||
// 生成子节点树
|
||||
buildChildren(node);
|
||||
// 排序子节点树
|
||||
// 排序子节点树
|
||||
sortChildren(node);
|
||||
|
||||
// 根据演算模型执行MiniMax检索
|
||||
// 对先手,搜索Max
|
||||
// 根据演算模型执行MiniMax检索
|
||||
// 对先手,搜索Max
|
||||
if (chessTemp.whosTurn() == NineChess::PLAYER1) {
|
||||
for (auto child : node->children) {
|
||||
value = alphaBetaPruning(depth - 1, alpha, beta, child);
|
||||
// 取最大值
|
||||
// 取最大值
|
||||
if (value > alpha)
|
||||
alpha = value;
|
||||
// 剪枝返回
|
||||
// 剪枝返回
|
||||
if (alpha >= beta) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
// 取最大值
|
||||
// 取最大值
|
||||
node->value = alpha;
|
||||
}
|
||||
// 对后手,搜索Min
|
||||
// 对后手,搜索Min
|
||||
else {
|
||||
for (auto child : node->children) {
|
||||
value = alphaBetaPruning(depth - 1, alpha, beta, child);
|
||||
// 取最小值
|
||||
// 取最小值
|
||||
if (value < beta)
|
||||
beta = value;
|
||||
// 剪枝返回
|
||||
// 剪枝返回
|
||||
if (alpha >= beta) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
// 取最小值
|
||||
// 取最小值
|
||||
node->value = beta;
|
||||
}
|
||||
// 返回
|
||||
// 返回
|
||||
return node->value;
|
||||
}
|
||||
|
||||
void NineChessAi_ab::reverse(const NineChess *node1, NineChess *node2, int i)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void NineChessAi_ab::turn(const NineChess *node1, NineChess *node2, int i)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void NineChessAi_ab::rotate(const NineChess *node1, NineChess *node2, int i)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool NineChessAi_ab::isInCache(Node * node, int &value)
|
||||
{
|
||||
/* NineChess tempData;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
reverse(node, &tempData, i);
|
||||
for (int j = 0; j < 6; j++) {
|
||||
turn(node, &tempData, j);
|
||||
int n = chess.rule.hasX ? 8 : 4;
|
||||
for (int k = 0; k < n; k++) {
|
||||
rotate(node, &tempData, k);
|
||||
for (auto i : dataCache) {
|
||||
if (compare(i, &tempData) == 0) {
|
||||
value = i.value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
#ifndef NINECHESSAI_AB
|
||||
#ifndef NINECHESSAI_AB
|
||||
#define NINECHESSAI_AB
|
||||
|
||||
#include "ninechess.h"
|
||||
#include <list>
|
||||
|
||||
// 注意:NineChess类不是线程安全的!
|
||||
// 所以不能在ai类中修改NineChess类的静态成员变量,切记!
|
||||
// 注意:NineChess类不是线程安全的!
|
||||
// 所以不能在ai类中修改NineChess类的静态成员变量,切记!
|
||||
|
||||
|
||||
class NineChessAi_ab
|
||||
{
|
||||
public:
|
||||
// 定义一个节点结构体
|
||||
// 定义一个节点结构体
|
||||
struct Node{
|
||||
int value; // 节点的值
|
||||
short move_; // 招法的命令行指令,图上标示为节点前的连线
|
||||
struct Node * parent; // 父节点
|
||||
list<struct Node *> children; // 子节点列表
|
||||
int value; // 节点的值
|
||||
short move_; // 招法的命令行指令,图上标示为节点前的连线
|
||||
struct Node * parent; // 父节点
|
||||
list<struct Node *> children; // 子节点列表
|
||||
};
|
||||
|
||||
public:
|
||||
|
@ -28,32 +28,44 @@ public:
|
|||
void quit() { requiredQuit = true; }
|
||||
|
||||
protected:
|
||||
// 建立子节点
|
||||
// 建立子节点
|
||||
void buildChildren(Node *node);
|
||||
// 子节点排序
|
||||
// 子节点排序
|
||||
void sortChildren(Node *node);
|
||||
// 清空节点树
|
||||
// 清空节点树
|
||||
void deleteTree(Node *node);
|
||||
|
||||
// 评价函数
|
||||
// 评价函数
|
||||
int evaluate(Node *node);
|
||||
// Alpha-Beta剪枝算法
|
||||
// Alpha-Beta剪枝算法
|
||||
int alphaBetaPruning(int depth, int alpha, int beta, Node *node);
|
||||
|
||||
// 局面逆序
|
||||
void reverse(const NineChess *node1, NineChess *node2, int i);
|
||||
// 局面层次翻转
|
||||
void turn(const NineChess *node1, NineChess *node2, int i);
|
||||
// 局面旋转
|
||||
void rotate(const NineChess *node1, NineChess *node2, int i);
|
||||
// 判断是否在缓存中
|
||||
bool isInCache(Node * node, int &value);
|
||||
|
||||
private:
|
||||
// 原始模型
|
||||
// 原始模型
|
||||
NineChess chess;
|
||||
// 演算用的模型
|
||||
// 演算用的模型
|
||||
NineChess chessTemp;
|
||||
|
||||
// 根节点
|
||||
// 根节点
|
||||
Node * rootNode;
|
||||
// 局面数据缓存区
|
||||
list<NineChess> dataCache;
|
||||
// 局面数据缓存区最大大小
|
||||
size_t cacheMaxSize;
|
||||
|
||||
// 标识,用于跳出剪枝算法,立即返回
|
||||
// 标识,用于跳出剪枝算法,立即返回
|
||||
bool requiredQuit;
|
||||
// 剪枝算法的层深
|
||||
// 剪枝算法的层深
|
||||
int depth;
|
||||
// 定义极大值,等于32位有符号整形数字的最大值
|
||||
// 定义极大值,等于32位有符号整形数字的最大值
|
||||
static const int infinity = 0x7fffffff;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# 九联棋 NineChess
|
||||
## 古老的游戏
|
||||
### 莫里斯九子棋
|
||||
![莫里斯九子棋](./Wiki/莫里斯九子棋.PNG "Optional title")
|
||||
![莫里斯九子棋](./screenshot/莫里斯九子棋.PNG "Optional title")
|
||||
|
||||
九子棋(Nine Men's Morris)是一个非常古老的智力的游戏。其历史甚至可以追溯到公元前1400多年的古埃及时代。
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
|||
+ 与莫里斯九子棋类似,但一方仅剩3子时不能飞子。
|
||||
|
||||
### 打三棋(12子棋)
|
||||
![12子棋](./Wiki/12子棋.PNG "Optional title")
|
||||
![12子棋](./screenshot/12子棋.PNG "Optional title")
|
||||
|
||||
1. 双方各12颗子,棋盘有斜线;
|
||||
2. 摆棋阶段被提子的位置不能再摆子,直到走棋阶段;
|
||||
|
@ -26,7 +26,7 @@
|
|||
6. 其它规则与成三棋基本相同。
|
||||
|
||||
### 九连棋
|
||||
![九连棋](./Wiki/九连棋.PNG "Optional title")
|
||||
![九连棋](./screenshot/九连棋.PNG "Optional title")
|
||||
|
||||
1. 规则与成三棋基本相同,只是它的棋子有序号;
|
||||
2. 相同序号、位置的“三连”不能重复提子;
|
||||
|
@ -35,7 +35,7 @@
|
|||
|
||||
## 应用程序说明
|
||||
### 用户界面
|
||||
![GUI](./Wiki/GUI.PNG "Optional title")
|
||||
![GUI](./screenshot/GUI.PNG "Optional title")
|
||||
|
||||
### 系统支持
|
||||
+ Windows版支持64位Windows 7、8、10系统,不支持32位系统及Windows XP。
|
||||
|
|
Loading…
Reference in New Issue