ai勉强能动,但不能正确使用,临时存一下,不要拉取使用!
This commit is contained in:
parent
a99577d089
commit
41917c1d74
|
@ -1,10 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE QtCreatorProject>
|
||||
<!-- Written by QtCreator 4.7.2, 2018-12-01T00:15:14. -->
|
||||
<!-- Written by QtCreator 4.6.1, 2018-12-02T12:38:12. -->
|
||||
<qtcreator>
|
||||
<data>
|
||||
<variable>EnvironmentId</variable>
|
||||
<value type="QByteArray">{9a8c5f9d-1814-40d9-ab01-983c45f229c5}</value>
|
||||
<value type="QByteArray">{fba36f69-c7a3-4c3f-91d4-7c71ad79549c}</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.ActiveTarget</variable>
|
||||
|
@ -54,22 +54,19 @@
|
|||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.PluginSettings</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<valuelist type="QVariantList" key="ClangCodeModel.CustomCommandLineKey"/>
|
||||
<value type="bool" key="ClangCodeModel.UseGlobalConfig">true</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap"/>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Target.0</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop Qt 5.9.7 GCC 64bit</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop Qt 5.9.7 GCC 64bit</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">qt.qt5.597.gcc_64_kit</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop Qt 5.11.0 MSVC2017 64bit</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop Qt 5.11.0 MSVC2017 64bit</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">qt.qt5.5110.win64_msvc2017_64_kit</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/media/sniper/Work/My program/QT/NineChess/build-ninechess-Desktop_Qt_5_9_7_GCC_64bit-Debug</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">E:/My program/QT/NineChess/build-ninechess-Desktop_Qt_5_11_0_MSVC2017_64bit-Debug</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
|
@ -87,10 +84,7 @@
|
|||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
||||
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
|
||||
<value type="QString">-w</value>
|
||||
<value type="QString">-r</value>
|
||||
</valuelist>
|
||||
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
|
||||
|
@ -106,10 +100,7 @@
|
|||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
||||
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
|
||||
<value type="QString">-w</value>
|
||||
<value type="QString">-r</value>
|
||||
</valuelist>
|
||||
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
|
||||
|
@ -129,7 +120,7 @@
|
|||
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/media/sniper/Work/My program/QT/NineChess/build-ninechess-Desktop_Qt_5_9_7_GCC_64bit-Release</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">E:/My program/QT/NineChess/build-ninechess-Desktop_Qt_5_11_0_MSVC2017_64bit-Release</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
|
@ -147,10 +138,7 @@
|
|||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
||||
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
|
||||
<value type="QString">-w</value>
|
||||
<value type="QString">-r</value>
|
||||
</valuelist>
|
||||
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
|
||||
|
@ -166,10 +154,7 @@
|
|||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
||||
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
|
||||
<value type="QString">-w</value>
|
||||
<value type="QString">-r</value>
|
||||
</valuelist>
|
||||
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
|
||||
|
@ -189,7 +174,7 @@
|
|||
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.2">
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/media/sniper/Work/My program/QT/NineChess/build-ninechess-Desktop_Qt_5_9_7_GCC_64bit-Profile</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">E:/My program/QT/NineChess/build-ninechess-Desktop_Qt_5_11_0_MSVC2017_64bit-Profile</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
|
@ -207,10 +192,7 @@
|
|||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
||||
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
|
||||
<value type="QString">-w</value>
|
||||
<value type="QString">-r</value>
|
||||
</valuelist>
|
||||
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
|
||||
|
@ -226,10 +208,7 @@
|
|||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
||||
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
|
||||
<value type="QString">-w</value>
|
||||
<value type="QString">-r</value>
|
||||
</valuelist>
|
||||
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
|
||||
|
@ -257,7 +236,7 @@
|
|||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy Configuration</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">部署设置</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
|
||||
</valuemap>
|
||||
|
@ -307,12 +286,13 @@
|
|||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">ninechess</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration:/media/sniper/Work/My program/QT/NineChess/NineChess/ninechess.pro</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration:E:/My program/QT/NineChess/NineChess/ninechess.pro</value>
|
||||
<value type="bool" key="QmakeProjectManager.QmakeRunConfiguration.UseLibrarySearchPath">true</value>
|
||||
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.CommandLineArguments"></value>
|
||||
<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">/media/sniper/Work/My program/QT/NineChess/build-ninechess-Desktop_Qt_5_9_7_GCC_64bit-Debug</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>
|
||||
|
|
|
@ -16,8 +16,7 @@ AiThread::~AiThread()
|
|||
void AiThread::setAi(const NineChess &chess)
|
||||
{
|
||||
mutex.lock();
|
||||
this->chess = chess;
|
||||
ai_ab.setChess(chess);
|
||||
this->chess = &chess;
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
|
@ -26,7 +25,7 @@ void AiThread::run()
|
|||
// 测试用数据
|
||||
int iTemp = 0;
|
||||
|
||||
while (true) {
|
||||
forever{
|
||||
if (isInterruptionRequested())
|
||||
return;
|
||||
mutex.lock();
|
||||
|
@ -34,6 +33,12 @@ void AiThread::run()
|
|||
pauseCondition.wait(&mutex);
|
||||
mutex.unlock();
|
||||
|
||||
ai_ab.setChess(*chess);
|
||||
ai_ab.alphaBetaPruning(1);
|
||||
const char * str = ai_ab.bestMove();
|
||||
qDebug() << str;
|
||||
emit command(str);
|
||||
|
||||
// 测试用
|
||||
qDebug() << "thread running " << iTemp << "ms";
|
||||
msleep(250);
|
||||
|
|
|
@ -36,8 +36,8 @@ private:
|
|||
// 等待条件,这里没用到,留着以后扩展用
|
||||
QWaitCondition pauseCondition;
|
||||
|
||||
// 棋类
|
||||
NineChess chess;
|
||||
// 主线程棋对象的引用
|
||||
const NineChess *chess;
|
||||
// Alpha-Beta剪枝算法类
|
||||
NineChessAi_ab ai_ab;
|
||||
};
|
||||
|
|
|
@ -149,7 +149,6 @@ void GameController::gameReset()
|
|||
currentRow = 0;
|
||||
manualListModel.insertRow(0);
|
||||
manualListModel.setData(manualListModel.index(0), chess.getCmdLine());
|
||||
|
||||
// 发出信号通知主窗口更新LCD显示
|
||||
QTime qtime = QTime(0, 0, 0, 0).addMSecs(time1);
|
||||
emit time1Changed(qtime.toString("mm:ss.zzz"));
|
||||
|
@ -409,12 +408,9 @@ bool GameController::actionPiece(QPointF pos)
|
|||
if (chess.getAction() == NineChess::ACTION_PLACE) {
|
||||
result = placePiece(pos);
|
||||
}// 去子
|
||||
else if (chess.getAction() == NineChess::ACTION_REMOVE) {
|
||||
result = removePiece(pos);
|
||||
else if (chess.getAction() == NineChess::ACTION_CAPTURE) {
|
||||
result = capturePiece(pos);
|
||||
}
|
||||
// 如果完成后进入中局,则删除禁点
|
||||
//if (chess.getPhase() == NineChess::GAME_MID && chess.getRule()->hasForbidden)
|
||||
// cleanForbidden();
|
||||
break;
|
||||
|
||||
case NineChess::GAME_MID:
|
||||
|
@ -427,8 +423,8 @@ bool GameController::actionPiece(QPointF pos)
|
|||
// 如果移子不成功,尝试重新选子
|
||||
result = movePiece(pos);
|
||||
}// 去子
|
||||
else if (chess.getAction() == NineChess::ACTION_REMOVE) {
|
||||
result = removePiece(pos);
|
||||
else if (chess.getAction() == NineChess::ACTION_CAPTURE) {
|
||||
result = capturePiece(pos);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -502,8 +498,12 @@ bool GameController::placePiece(QPointF pos)
|
|||
// 发信号更新状态栏
|
||||
message = QString::fromStdString(chess.getTip());
|
||||
emit statusBarChanged(message);
|
||||
// 播放音效
|
||||
playSound(":/sound/resources/sound/drog.wav");
|
||||
// 播放成三音效
|
||||
if (chess.getAction() == NineChess::ACTION_CAPTURE)
|
||||
playSound(":/sound/resources/sound/capture.wav");
|
||||
// 播放落下棋子音效
|
||||
else
|
||||
playSound(":/sound/resources/sound/drog.wav");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -523,8 +523,12 @@ bool GameController::movePiece(QPointF pos)
|
|||
// 发信号更新状态栏
|
||||
message = QString::fromStdString(chess.getTip());
|
||||
emit statusBarChanged(message);
|
||||
// 播放音效
|
||||
playSound(":/sound/resources/sound/move.wav");
|
||||
// 播放成三音效
|
||||
if (chess.getAction() == NineChess::ACTION_CAPTURE)
|
||||
playSound(":/sound/resources/sound/capture.wav");
|
||||
// 播放移动棋子音效
|
||||
else
|
||||
playSound(":/sound/resources/sound/move.wav");
|
||||
return true;
|
||||
}
|
||||
// 如果移子不成功,尝试重新选子
|
||||
|
@ -535,13 +539,13 @@ bool GameController::movePiece(QPointF pos)
|
|||
}
|
||||
|
||||
// 去子
|
||||
bool GameController::removePiece(QPointF pos)
|
||||
bool GameController::capturePiece(QPointF pos)
|
||||
{
|
||||
int c, p;
|
||||
if (!scene.pos2cp(pos, c, p)) {
|
||||
return false;
|
||||
}
|
||||
if (!chess.remove(c, p)) {
|
||||
if (!chess.capture(c, p)) {
|
||||
// 播放禁止音效
|
||||
playSound(":/sound/resources/sound/forbidden.wav");
|
||||
return false;
|
||||
|
@ -699,5 +703,25 @@ bool GameController::updateScence(NineChess &chess)
|
|||
|
||||
animationGroup->start(QAbstractAnimation::DeleteWhenStopped);
|
||||
|
||||
// AI设置
|
||||
if (&chess == &(this->chess)) {
|
||||
// 如果还未决出胜负
|
||||
if (chess.whoWin() == NineChess::NOBODY) {
|
||||
if (chess.whosTurn() == NineChess::PLAYER1) {
|
||||
ai1.resume();
|
||||
ai2.pause();
|
||||
}
|
||||
else {
|
||||
ai1.pause();
|
||||
ai2.resume();
|
||||
}
|
||||
}
|
||||
// 如果已经决出胜负
|
||||
else {
|
||||
ai1.pause();
|
||||
ai1.pause();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -90,7 +90,7 @@ protected:
|
|||
// 移动旧子
|
||||
bool movePiece(QPointF pos);
|
||||
// 去子
|
||||
bool removePiece(QPointF pos);
|
||||
bool capturePiece(QPointF pos);
|
||||
|
||||
private:
|
||||
// 棋对象的数据模型
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
** Mail: liuweilhy@163.com
|
||||
** This file is part of the NineChess game.
|
||||
****************************************************************************/
|
||||
|
||||
#if _MSC_VER >= 1600
|
||||
#pragma execution_character_set("utf-8")
|
||||
#endif
|
||||
|
@ -200,8 +201,8 @@ bool NineChess::setData(const struct Rule *rule, int s, int t, int step, int fla
|
|||
data.action = ACTION_CHOOSE;
|
||||
else if (flags & ACTION_PLACE)
|
||||
data.action = ACTION_PLACE;
|
||||
else if (flags & ACTION_REMOVE)
|
||||
data.action = ACTION_REMOVE;
|
||||
else if (flags & ACTION_CAPTURE)
|
||||
data.action = ACTION_CAPTURE;
|
||||
else
|
||||
return false;
|
||||
|
||||
|
@ -236,7 +237,7 @@ bool NineChess::setData(const struct Rule *rule, int s, int t, int step, int fla
|
|||
data.player2_InHand = p2_InHand < data.player2_InHand ? p2_InHand : data.player2_InHand;
|
||||
|
||||
// 设置去子状态时的剩余尚待去除子数
|
||||
if (flags & ACTION_REMOVE) {
|
||||
if (flags & ACTION_CAPTURE) {
|
||||
if (num_NeedRemove >= 0 && num_NeedRemove < 3)
|
||||
data.num_NeedRemove = num_NeedRemove;
|
||||
}
|
||||
|
@ -398,7 +399,7 @@ bool NineChess::reset()
|
|||
winner = NOBODY;
|
||||
|
||||
// 当前棋局(3×8)
|
||||
memset(board, 0, sizeof(board));
|
||||
memset(board, 0, sizeof(data.board));
|
||||
|
||||
// 盘面子数归零
|
||||
data.player1_Remain = data.player2_Remain = 0;
|
||||
|
@ -611,7 +612,7 @@ bool NineChess::place(int c, int p, long time_p /* = -1*/)
|
|||
// 设置去子数目
|
||||
data.num_NeedRemove = rule.removeMore ? n : 1;
|
||||
// 进入去子状态
|
||||
data.action = ACTION_REMOVE;
|
||||
data.action = ACTION_CAPTURE;
|
||||
}
|
||||
setTip();
|
||||
return true;
|
||||
|
@ -660,7 +661,7 @@ bool NineChess::place(int c, int p, long time_p /* = -1*/)
|
|||
// 设置去子数目
|
||||
data.num_NeedRemove = rule.removeMore ? n : 1;
|
||||
// 进入去子状态
|
||||
data.action = ACTION_REMOVE;
|
||||
data.action = ACTION_CAPTURE;
|
||||
setTip();
|
||||
}
|
||||
setTip();
|
||||
|
@ -670,13 +671,13 @@ bool NineChess::place(int c, int p, long time_p /* = -1*/)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool NineChess::remove(int c, int p, long time_p /* = -1*/)
|
||||
bool NineChess::capture(int c, int p, long time_p /* = -1*/)
|
||||
{
|
||||
// 如果局面为"未开局"或“结局”,返回false
|
||||
if (data.phase == GAME_NOTSTARTED || data.phase == GAME_OVER)
|
||||
return false;
|
||||
// 如非“去子”状态,返回false
|
||||
if (data.action != ACTION_REMOVE)
|
||||
if (data.action != ACTION_CAPTURE)
|
||||
return false;
|
||||
// 如果去子完成,返回false
|
||||
if (data.num_NeedRemove <= 0)
|
||||
|
@ -685,11 +686,9 @@ bool NineChess::remove(int c, int p, long time_p /* = -1*/)
|
|||
long player_ms = -1;
|
||||
int pos = cp2pos(c, p);
|
||||
// 对手
|
||||
enum Players opponent = PLAYER2;
|
||||
if (data.turn == PLAYER2)
|
||||
opponent = PLAYER1;
|
||||
// 判断去子不是对手棋
|
||||
if (getWhosPiece(c, p) != opponent)
|
||||
char opponent = data.turn == PLAYER1 ? 0x20 : 0x10;
|
||||
// 判断去子是不是对手棋
|
||||
if (!(opponent & board[pos]))
|
||||
return false;
|
||||
|
||||
// 如果当前子是否处于“三连”之中,且对方还未全部处于“三连”之中
|
||||
|
@ -810,6 +809,267 @@ bool NineChess::choose(int c, int p)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool NineChess::place(int pos)
|
||||
{
|
||||
// 如果局面为“结局”,返回false
|
||||
if (data.phase == GAME_OVER)
|
||||
return false;
|
||||
// 如果局面为“未开局”,则开具
|
||||
if (data.phase == GAME_NOTSTARTED)
|
||||
start();
|
||||
|
||||
// 如非“落子”状态,返回false
|
||||
if (data.action != ACTION_PLACE)
|
||||
return false;
|
||||
// 如果落子位置在棋盘外、已有子点或禁点,返回false
|
||||
if (!inBoard[pos] || board[pos])
|
||||
return false;
|
||||
|
||||
// 对于开局落子
|
||||
char piece = '\x00';
|
||||
int n = 0;
|
||||
if (data.phase == GAME_OPENING) {
|
||||
// 先手下
|
||||
if (data.turn == PLAYER1)
|
||||
{
|
||||
piece = '\x11' + rule.numOfChess - data.player1_InHand;
|
||||
data.player1_InHand--;
|
||||
data.player1_Remain++;
|
||||
}
|
||||
// 后手下
|
||||
else
|
||||
{
|
||||
piece = '\x21' + rule.numOfChess - data.player2_InHand;
|
||||
data.player2_InHand--;
|
||||
data.player2_Remain++;
|
||||
}
|
||||
board[pos] = piece;
|
||||
move_ = pos;
|
||||
currentPos = pos;
|
||||
data.step++;
|
||||
// 如果决出胜负
|
||||
if (win()) {
|
||||
setTip();
|
||||
return true;
|
||||
}
|
||||
|
||||
n = addMills(currentPos);
|
||||
// 开局阶段未成三
|
||||
if (n == 0) {
|
||||
// 如果双方都无未放置的棋子
|
||||
if (data.player1_InHand == 0 && data.player2_InHand == 0) {
|
||||
// 进入中局阶段
|
||||
data.phase = GAME_MID;
|
||||
// 进入选子状态
|
||||
data.action = ACTION_CHOOSE;
|
||||
// 清除禁点
|
||||
cleanForbidden();
|
||||
// 设置轮到谁走
|
||||
if (rule.isDefensiveMoveFirst) {
|
||||
data.turn = PLAYER2;
|
||||
}
|
||||
else {
|
||||
data.turn = PLAYER1;
|
||||
}
|
||||
|
||||
// 再决胜负
|
||||
if (win()) {
|
||||
setTip();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// 如果双方还有子
|
||||
else {
|
||||
// 设置轮到谁走
|
||||
changeTurn();
|
||||
}
|
||||
}
|
||||
// 如果成三
|
||||
else {
|
||||
// 设置去子数目
|
||||
data.num_NeedRemove = rule.removeMore ? n : 1;
|
||||
// 进入去子状态
|
||||
data.action = ACTION_CAPTURE;
|
||||
}
|
||||
setTip();
|
||||
return true;
|
||||
}
|
||||
|
||||
// 对于中局落子
|
||||
else if (data.phase == GAME_MID) {
|
||||
// 如果落子不合法
|
||||
if ((data.turn == PLAYER1 && (data.player1_Remain > rule.numAtLest || !rule.canFly)) ||
|
||||
(data.turn == PLAYER2 && (data.player2_Remain > rule.numAtLest || !rule.canFly))) {
|
||||
int i;
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (pos == moveTable[currentPos][i])
|
||||
break;
|
||||
}
|
||||
// 不在招法表中
|
||||
if (i == 4)
|
||||
return false;
|
||||
}
|
||||
// 移子
|
||||
move_ = currentPos << 8 + pos;
|
||||
board[pos] = board[currentPos];
|
||||
board[currentPos] = '\x00';
|
||||
currentPos = pos;
|
||||
data.step++;
|
||||
n = addMills(currentPos);
|
||||
|
||||
// 中局阶段未成三
|
||||
if (n == 0) {
|
||||
// 进入选子状态
|
||||
data.action = ACTION_CHOOSE;
|
||||
// 设置轮到谁走
|
||||
changeTurn();
|
||||
// 如果决出胜负
|
||||
if (win()) {
|
||||
setTip();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// 中局阶段成三
|
||||
else {
|
||||
// 设置去子数目
|
||||
data.num_NeedRemove = rule.removeMore ? n : 1;
|
||||
// 进入去子状态
|
||||
data.action = ACTION_CAPTURE;
|
||||
setTip();
|
||||
}
|
||||
setTip();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NineChess::capture(int pos)
|
||||
{
|
||||
// 如果局面为"未开局"或“结局”,返回false
|
||||
if (data.phase == GAME_NOTSTARTED || data.phase == GAME_OVER)
|
||||
return false;
|
||||
// 如非“去子”状态,返回false
|
||||
if (data.action != ACTION_CAPTURE)
|
||||
return false;
|
||||
// 如果去子完成,返回false
|
||||
if (data.num_NeedRemove <= 0)
|
||||
return false;
|
||||
// 对手
|
||||
char opponent = data.turn == PLAYER1 ? 0x20 : 0x10;
|
||||
// 判断去子是不是对手棋
|
||||
if (!(opponent & board[pos]))
|
||||
return false;
|
||||
|
||||
// 如果当前子是否处于“三连”之中,且对方还未全部处于“三连”之中
|
||||
if (isInMills(pos) && !isAllInMills(opponent)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 去子(设置禁点)
|
||||
if (rule.hasForbidden && data.phase == GAME_OPENING)
|
||||
board[pos] = '\x0f';
|
||||
else // 去子
|
||||
board[pos] = '\x00';
|
||||
if (data.turn == PLAYER1)
|
||||
data.player2_Remain--;
|
||||
else if (data.turn == PLAYER2)
|
||||
data.player1_Remain--;
|
||||
move_ = -pos;
|
||||
currentPos = 0;
|
||||
data.num_NeedRemove--;
|
||||
data.step++;
|
||||
// 去子完成
|
||||
|
||||
// 如果决出胜负
|
||||
if (win()) {
|
||||
setTip();
|
||||
return true;
|
||||
}
|
||||
// 还有其余的子要去吗
|
||||
if (data.num_NeedRemove > 0) {
|
||||
// 继续去子
|
||||
return true;
|
||||
}
|
||||
// 所有去子都完成了
|
||||
else {
|
||||
// 开局阶段
|
||||
if (data.phase == GAME_OPENING) {
|
||||
// 如果双方都无未放置的棋子
|
||||
if (data.player1_InHand == 0 && data.player2_InHand == 0) {
|
||||
// 进入中局阶段
|
||||
data.phase = GAME_MID;
|
||||
// 进入选子状态
|
||||
data.action = ACTION_CHOOSE;
|
||||
// 清除禁点
|
||||
cleanForbidden();
|
||||
// 设置轮到谁走
|
||||
if (rule.isDefensiveMoveFirst) {
|
||||
data.turn = PLAYER2;
|
||||
}
|
||||
else {
|
||||
data.turn = PLAYER1;
|
||||
}
|
||||
// 再决胜负
|
||||
if (win()) {
|
||||
setTip();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// 如果双方还有子
|
||||
else {
|
||||
// 进入落子状态
|
||||
data.action = ACTION_PLACE;
|
||||
// 设置轮到谁走
|
||||
changeTurn();
|
||||
// 如果决出胜负
|
||||
if (win()) {
|
||||
setTip();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 中局阶段
|
||||
else {
|
||||
// 进入选子状态
|
||||
data.action = ACTION_CHOOSE;
|
||||
// 设置轮到谁走
|
||||
changeTurn();
|
||||
// 如果决出胜负
|
||||
if (win()) {
|
||||
setTip();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
setTip();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NineChess::choose(int pos)
|
||||
{
|
||||
// 如果局面不是"中局”,返回false
|
||||
if (data.phase != GAME_MID)
|
||||
return false;
|
||||
// 如非“选子”或“落子”状态,返回false
|
||||
if (data.action != ACTION_CHOOSE && data.action != ACTION_PLACE)
|
||||
return false;
|
||||
char t = data.turn == PLAYER1 ? 0x10 : 0x20;
|
||||
// 判断选子是否可选
|
||||
if (board[pos] & t) {
|
||||
// 判断pos处的棋子是否被“闷”
|
||||
if (isSurrounded(pos)) {
|
||||
return false;
|
||||
}
|
||||
// 选子
|
||||
currentPos = pos;
|
||||
// 选子完成,进入落子状态
|
||||
data.action = ACTION_PLACE;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NineChess::giveup(Players loser)
|
||||
{
|
||||
if (data.phase == GAME_MID || data.phase == GAME_OPENING)
|
||||
|
@ -872,7 +1132,7 @@ bool NineChess::command(const char *cmd)
|
|||
if (mm >= 0 && ss >= 0 && mss >= 0)
|
||||
tm = mm * 60000 + ss * 1000 + mss;
|
||||
}
|
||||
return remove(c1, p1, tm);
|
||||
return capture(c1, p1, tm);
|
||||
}
|
||||
|
||||
// 落子
|
||||
|
@ -900,6 +1160,21 @@ bool NineChess::command(const char *cmd)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool NineChess::command(int16_t move)
|
||||
{
|
||||
if (move < 0) {
|
||||
return capture(-move);
|
||||
}
|
||||
else if (move & 0x00ff) {
|
||||
return place(move & 0x00ff);
|
||||
}
|
||||
else {
|
||||
if (choose(move >> 8))
|
||||
return place(move & 0x00ff);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline long NineChess::update(long time_p /*= -1*/)
|
||||
{
|
||||
long ret = -1;
|
||||
|
@ -1079,7 +1354,7 @@ int NineChess::addMills(int pos)
|
|||
//0x 00 00 00 00 00 00 00 00
|
||||
// unused unused piece1 pos1 piece2 pos2 piece3 pos3
|
||||
//piece1、piece2、piece3按照序号从小到大顺序排放
|
||||
long long mill = 0;
|
||||
uint64_t mill = 0;
|
||||
int n = 0;
|
||||
int p[3], min, temp;
|
||||
char m = board[pos] & '\x30';
|
||||
|
@ -1104,12 +1379,12 @@ int NineChess::addMills(int pos)
|
|||
}
|
||||
}
|
||||
// 成三
|
||||
mill = (((long long)board[p[0]]) << 40)
|
||||
+ (((long long)p[0]) << 32)
|
||||
+ (((long long)board[p[1]]) << 24)
|
||||
+ (((long long)p[1]) << 16)
|
||||
+ (((long long)board[p[2]]) << 8)
|
||||
+ (long long)p[2];
|
||||
mill = (((uint64_t)board[p[0]]) << 40)
|
||||
+ (((uint64_t)p[0]) << 32)
|
||||
+ (((uint64_t)board[p[1]]) << 24)
|
||||
+ (((uint64_t)p[1]) << 16)
|
||||
+ (((uint64_t)board[p[2]]) << 8)
|
||||
+ (uint64_t)p[2];
|
||||
|
||||
// 如果允许相同三连反复去子
|
||||
if (rule.canRepeated) {
|
||||
|
@ -1119,7 +1394,7 @@ int NineChess::addMills(int pos)
|
|||
else
|
||||
{
|
||||
// 迭代器
|
||||
list<long long>::iterator itor;
|
||||
list<uint64_t>::iterator itor;
|
||||
// 遍历
|
||||
for (itor = data.millList.begin(); itor != data.millList.end(); itor++)
|
||||
{
|
||||
|
@ -1137,6 +1412,17 @@ int NineChess::addMills(int pos)
|
|||
return n;
|
||||
}
|
||||
|
||||
bool NineChess::isAllInMills(char ch)
|
||||
{
|
||||
for (int i = SEAT; i < SEAT * (RING+1); i++)
|
||||
if (board[i] & ch) {
|
||||
if (!isInMills(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NineChess::isAllInMills(enum Players player)
|
||||
{
|
||||
char ch = '\x00';
|
||||
|
@ -1146,15 +1432,7 @@ bool NineChess::isAllInMills(enum Players player)
|
|||
ch = '\x20';
|
||||
else
|
||||
return true;
|
||||
for (int i = 1; i <= RING; i++)
|
||||
for (int j = 0; j < SEAT; j++) {
|
||||
if (board[i*SEAT + j] & ch) {
|
||||
if (!isInMills(i*SEAT + j)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return isAllInMills(ch);
|
||||
}
|
||||
|
||||
// 判断玩家的棋子是否被围
|
||||
|
@ -1178,14 +1456,8 @@ bool NineChess::isSurrounded(int pos)
|
|||
return false;
|
||||
}
|
||||
|
||||
// 判断玩家的棋子是否全部被围
|
||||
bool NineChess::isAllSurrounded(enum Players ply)
|
||||
bool NineChess::isAllSurrounded(char ch)
|
||||
{
|
||||
char t = '\x30';
|
||||
if (ply == PLAYER1)
|
||||
t &= '\x10';
|
||||
else if (ply == PLAYER2)
|
||||
t &= '\x20';
|
||||
// 如果摆满
|
||||
if (data.player1_Remain + data.player2_Remain >= SEAT * RING)
|
||||
return true;
|
||||
|
@ -1196,23 +1468,30 @@ bool NineChess::isAllSurrounded(enum Players ply)
|
|||
return false;
|
||||
}
|
||||
// 查询整个棋盘
|
||||
for (int i = 1; i <= RING; i++)
|
||||
{
|
||||
for (int j = 0; j < SEAT; j++)
|
||||
{
|
||||
int movePos;
|
||||
if (t & board[i*SEAT + j]) {
|
||||
for (int k = 0; k < 4; k++) {
|
||||
movePos = moveTable[i*SEAT + j][k];
|
||||
if (movePos && !board[movePos])
|
||||
return false;
|
||||
}
|
||||
char movePos;
|
||||
for (int i = 1; i < SEAT * (RING + 1); i++) {
|
||||
if (ch & board[i]) {
|
||||
for (int k = 0; k < 4; k++) {
|
||||
movePos = moveTable[i][k];
|
||||
if (movePos && !board[movePos])
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 判断玩家的棋子是否全部被围
|
||||
bool NineChess::isAllSurrounded(enum Players ply)
|
||||
{
|
||||
char t = '\x30';
|
||||
if (ply == PLAYER1)
|
||||
t &= '\x10';
|
||||
else if (ply == PLAYER2)
|
||||
t &= '\x20';
|
||||
return isAllSurrounded(t);
|
||||
}
|
||||
|
||||
void NineChess::cleanForbidden()
|
||||
{
|
||||
for (int i = 1; i <= RING; i++)
|
||||
|
@ -1245,7 +1524,7 @@ void NineChess::setTip()
|
|||
tip = "轮到玩家2落子,剩余" + std::to_string(data.player2_InHand) + "子";
|
||||
}
|
||||
}
|
||||
else if (data.action == ACTION_REMOVE) {
|
||||
else if (data.action == ACTION_CAPTURE) {
|
||||
if (data.turn == PLAYER1) {
|
||||
tip = "轮到玩家1去子,需去" + std::to_string(data.num_NeedRemove) + "子";
|
||||
}
|
||||
|
@ -1263,7 +1542,7 @@ void NineChess::setTip()
|
|||
tip = "轮到玩家2选子移动";
|
||||
}
|
||||
}
|
||||
else if (data.action == ACTION_REMOVE) {
|
||||
else if (data.action == ACTION_CAPTURE) {
|
||||
if (data.turn == PLAYER1) {
|
||||
tip = "轮到玩家1去子,需去" + std::to_string(data.num_NeedRemove) + "子";
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@ using std::list;
|
|||
// 所以不能跨线程修改NineChess类的静态成员变量,切记!
|
||||
class NineChess
|
||||
{
|
||||
// AI友元类
|
||||
friend class NineChessAi_ab;
|
||||
public:
|
||||
// 5个静态成员常量
|
||||
// 3圈,禁止修改!
|
||||
|
@ -65,7 +67,7 @@ public:
|
|||
static const struct Rule RULES[RULENUM];
|
||||
|
||||
// 局面阶段标识
|
||||
enum Phases {
|
||||
enum Phases : uint16_t {
|
||||
GAME_NOTSTARTED = 0x0001, // 未开局
|
||||
GAME_OPENING = 0x0002, // 开局(摆棋)
|
||||
GAME_MID = 0x0004, // 中局(走棋)
|
||||
|
@ -73,7 +75,7 @@ public:
|
|||
};
|
||||
|
||||
// 玩家标识,轮流状态,胜负标识
|
||||
enum Players {
|
||||
enum Players : uint16_t {
|
||||
PLAYER1 = 0x0010, // 玩家1
|
||||
PLAYER2 = 0x0020, // 玩家2
|
||||
DRAW = 0x0040, // 双方和棋
|
||||
|
@ -81,10 +83,10 @@ public:
|
|||
};
|
||||
|
||||
// 动作状态标识
|
||||
enum Actions {
|
||||
enum Actions : uint16_t {
|
||||
ACTION_CHOOSE = 0x0100, // 选子
|
||||
ACTION_PLACE = 0x0200, // 落子
|
||||
ACTION_REMOVE = 0x0400 // 提子
|
||||
ACTION_CAPTURE = 0x0400 // 提子
|
||||
};
|
||||
|
||||
// 棋局结构体,包含当前棋盘数据
|
||||
|
@ -109,15 +111,15 @@ public:
|
|||
enum NineChess::Actions action;
|
||||
|
||||
// 玩家1剩余未放置子数
|
||||
char player1_InHand;
|
||||
int8_t player1_InHand;
|
||||
// 玩家2剩余未放置子数
|
||||
char player2_InHand;
|
||||
int8_t player2_InHand;
|
||||
// 玩家1盘面剩余子数
|
||||
char player1_Remain;
|
||||
int8_t player1_Remain;
|
||||
// 玩家1盘面剩余子数
|
||||
char player2_Remain;
|
||||
int8_t player2_Remain;
|
||||
// 尚待去除的子数
|
||||
char num_NeedRemove;
|
||||
int8_t num_NeedRemove;
|
||||
|
||||
/* 本打算用如下的结构体来表示“三连”
|
||||
struct Mill {
|
||||
|
@ -133,7 +135,7 @@ public:
|
|||
unused unused piece1 pos1 piece2 pos2 piece3 pos3
|
||||
*/
|
||||
// “三连列表”
|
||||
list <long long> millList;
|
||||
list <uint64_t> millList;
|
||||
};
|
||||
|
||||
private:
|
||||
|
@ -225,20 +227,27 @@ public:
|
|||
// 落子,在第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 capture(int c, int p, long time_p = -1);
|
||||
// 下面3个函数没有算法无关判断和无关操作
|
||||
bool choose(int pos);
|
||||
bool place(int pos);
|
||||
bool capture(int pos);
|
||||
// 认输
|
||||
bool giveup(Players loser);
|
||||
// 命令行解析函数
|
||||
bool command(int16_t move);
|
||||
bool command(const char *cmd);
|
||||
|
||||
protected:
|
||||
// 判断棋盘pos处的棋子处于几个“三连”中
|
||||
int isInMills(int pos);
|
||||
// 判断玩家的所有棋子是否都处于“三连”状态
|
||||
bool isAllInMills(char ch);
|
||||
bool isAllInMills(enum Players);
|
||||
// 判断玩家的棋子是否被围
|
||||
bool isSurrounded(int pos);
|
||||
// 判断玩家的棋子是否全部被围
|
||||
bool isAllSurrounded(char ch);
|
||||
bool isAllSurrounded(enum Players);
|
||||
// 三连加入列表
|
||||
int addMills(int pos);
|
||||
|
@ -285,7 +294,7 @@ private:
|
|||
移子:0x__??,__为移动前的位置,??为移动后的位置
|
||||
去子:0xFF??,??取位置补码,即为负数
|
||||
*/
|
||||
short move_;
|
||||
int16_t move_;
|
||||
|
||||
// 招法命令行用于棋谱的显示和解析
|
||||
// 当前招法的命令行指令,即一招棋谱
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
#include "ninechessai_ab.h"
|
||||
/****************************************************************************
|
||||
** by liuweilhy, 2018.11.29
|
||||
** Mail: liuweilhy@163.com
|
||||
** This file is part of the NineChess game.
|
||||
****************************************************************************/
|
||||
|
||||
#include "ninechessai_ab.h"
|
||||
#include <cmath>
|
||||
#include <time.h>
|
||||
|
||||
|
@ -9,7 +15,7 @@ depth(3) // 默认3层深度
|
|||
{
|
||||
rootNode = new Node;
|
||||
rootNode->value = 0;
|
||||
rootNode->move_ = 0;
|
||||
rootNode->move = 0;
|
||||
rootNode->parent = nullptr;
|
||||
}
|
||||
|
||||
|
@ -20,8 +26,89 @@ NineChessAi_ab::~NineChessAi_ab()
|
|||
|
||||
void NineChessAi_ab::buildChildren(Node *node)
|
||||
{
|
||||
char opponent;
|
||||
// 列出所有合法的下一招
|
||||
;
|
||||
switch (chessTemp.data.action)
|
||||
{
|
||||
case NineChess::ACTION_CHOOSE:
|
||||
case NineChess::ACTION_PLACE:
|
||||
// 对于开局落子
|
||||
if ((chessTemp.data.phase) & (NineChess::GAME_OPENING | NineChess::GAME_NOTSTARTED)) {
|
||||
for (int i = NineChess::SEAT; i < (NineChess::RING + 1)*NineChess::SEAT; i++) {
|
||||
if (!chessTemp.board[i]) {
|
||||
Node * newNode = new Node;
|
||||
newNode->parent = node;
|
||||
newNode->value = 0;
|
||||
newNode->move = i;
|
||||
node->children.push_back(newNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 对于中局移子
|
||||
else {
|
||||
char newPos;
|
||||
for (int i = NineChess::SEAT; i < (NineChess::RING + 1)*NineChess::SEAT; i++) {
|
||||
if (!chessTemp.choose(i))
|
||||
break;
|
||||
if ((chessTemp.data.turn == NineChess::PLAYER1 && (chessTemp.data.player1_Remain > chessTemp.rule.numAtLest || !chessTemp.rule.canFly)) ||
|
||||
(chessTemp.data.turn == NineChess::PLAYER2 && (chessTemp.data.player2_Remain > chessTemp.rule.numAtLest || !chessTemp.rule.canFly))) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
if (newPos == chessTemp.moveTable[i][j]) {
|
||||
Node * newNode = new Node;
|
||||
newNode->parent = node;
|
||||
newNode->value = 0;
|
||||
newNode->move = i << 8 + newPos;
|
||||
node->children.push_back(newNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int j = NineChess::SEAT; j < (NineChess::RING + 1)*NineChess::SEAT; j++) {
|
||||
if (newPos & chessTemp.board[j])
|
||||
break;
|
||||
Node * newNode = new Node;
|
||||
newNode->parent = node;
|
||||
newNode->value = 0;
|
||||
newNode->move = i << 8 + j;
|
||||
node->children.push_back(newNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case NineChess::ACTION_CAPTURE:
|
||||
opponent = chessTemp.data.turn == NineChess::PLAYER1 ? 0x20 : 0x10;
|
||||
// 全成三的情况
|
||||
if (chessTemp.isAllInMills(opponent)) {
|
||||
for (int i = NineChess::SEAT; i < (NineChess::RING + 1)*NineChess::SEAT; i++) {
|
||||
if (chessTemp.board[i] & opponent) {
|
||||
Node * newNode = new Node;
|
||||
newNode->parent = node;
|
||||
newNode->value = 0;
|
||||
newNode->move = -i;
|
||||
node->children.push_back(newNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = NineChess::SEAT; i < (NineChess::RING + 1)*NineChess::SEAT; i++) {
|
||||
if (chessTemp.board[i] & opponent) {
|
||||
if (chessTemp.isInMills(i))
|
||||
break;
|
||||
Node * newNode = new Node;
|
||||
newNode->parent = node;
|
||||
newNode->value = 0;
|
||||
newNode->move = -i;
|
||||
node->children.push_back(newNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void NineChessAi_ab::sortChildren(Node *node)
|
||||
|
@ -51,27 +138,95 @@ void NineChessAi_ab::setChess(const NineChess &chess)
|
|||
{
|
||||
this->chess = chess;
|
||||
chessTemp = chess;
|
||||
chessData = &(chessTemp.data);
|
||||
requiredQuit = false;
|
||||
// 生成棋子价值表
|
||||
for (int j = 0; j < NineChess::SEAT; j++)
|
||||
{
|
||||
// 对于0、2、4、6位(偶数位)
|
||||
if (!(j & 1)) {
|
||||
boardScore[1 * NineChess::SEAT + j] = 80;
|
||||
boardScore[2 * NineChess::SEAT + j] = 100;
|
||||
boardScore[3 * NineChess::SEAT + j] = 80;
|
||||
}
|
||||
// 对于有斜线情况下的1、3、5、7位(奇数位)
|
||||
else if(chessTemp.rule.hasObliqueLine) {
|
||||
boardScore[1 * NineChess::SEAT + j] = 70;
|
||||
boardScore[2 * NineChess::SEAT + j] = 90;
|
||||
boardScore[3 * NineChess::SEAT + j] = 70;
|
||||
}
|
||||
// 对于无斜线情况下的1、3、5、7位(奇数位)
|
||||
else {
|
||||
boardScore[1 * NineChess::SEAT + j] = 60;
|
||||
boardScore[2 * NineChess::SEAT + j] = 80;
|
||||
boardScore[3 * NineChess::SEAT + j] = 60;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int NineChessAi_ab::evaluate(Node *node)
|
||||
{
|
||||
// 初始评估值为0,对先手有利则增大,对后手有利则减小
|
||||
int value = 0;
|
||||
switch (chessData->phase)
|
||||
{
|
||||
case NineChess::GAME_NOTSTARTED:
|
||||
break;
|
||||
|
||||
// 开局和中局阶段用同样的评价方法
|
||||
case NineChess::GAME_OPENING:
|
||||
case NineChess::GAME_MID:
|
||||
// 按手棋数目计分,每子50分
|
||||
value += (chessData->player1_InHand) * 50 - (chessData->player2_InHand) * 50;
|
||||
// 按场上棋子计分
|
||||
for (int i = 1*NineChess::SEAT; i < NineChess::SEAT*(NineChess::RING+1); i++) {
|
||||
if (chessData->board[i] & 0x10)
|
||||
value += boardScore[i];
|
||||
else if (chessData->board[i] & 0x20)
|
||||
value -= boardScore[i];
|
||||
}
|
||||
switch (chessData->action)
|
||||
{
|
||||
// 选子和落子使用相同的评价方法
|
||||
case NineChess::ACTION_CHOOSE:
|
||||
case NineChess::ACTION_PLACE:
|
||||
break;
|
||||
// 如果形成去子状态,每有一个可去的子,算100分
|
||||
case NineChess::ACTION_CAPTURE:
|
||||
value += (chessData->turn == NineChess::PLAYER1) ? chessData->num_NeedRemove * 100 : -chessData->num_NeedRemove * 100;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
// 终局评价最简单
|
||||
case NineChess::GAME_OVER:
|
||||
if (chessData->player1_Remain < chessTemp.rule.numAtLest)
|
||||
value = -infinity;
|
||||
else if (chessData->player2_Remain < chessTemp.rule.numAtLest)
|
||||
value = infinity;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// 赋值返回
|
||||
node->value = value;
|
||||
return value;
|
||||
}
|
||||
|
||||
int NineChessAi_ab::alphaBetaPruning(int depth)
|
||||
{
|
||||
return alphaBetaPruning(depth, -infinity, infinity, rootNode);
|
||||
}
|
||||
|
||||
int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
|
||||
{
|
||||
// 评价值
|
||||
int value;
|
||||
if (!depth || !(node->children.size())) {
|
||||
if (!depth || chessTemp.data.phase == NineChess::GAME_OVER) {
|
||||
node->value = evaluate(node);
|
||||
return node->value;
|
||||
}
|
||||
|
@ -85,7 +240,11 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
|
|||
// 对先手,搜索Max
|
||||
if (chessTemp.whosTurn() == NineChess::PLAYER1) {
|
||||
for (auto child : node->children) {
|
||||
hashTable.push_back({chessTemp.data, 0, depth});
|
||||
chessTemp.command(child->move);
|
||||
value = alphaBetaPruning(depth - 1, alpha, beta, child);
|
||||
chessTemp.data = hashTable.back().data;
|
||||
hashTable.pop_back();
|
||||
// 取最大值
|
||||
if (value > alpha)
|
||||
alpha = value;
|
||||
|
@ -100,7 +259,11 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
|
|||
// 对后手,搜索Min
|
||||
else {
|
||||
for (auto child : node->children) {
|
||||
hashTable.push_back({ chessTemp.data, 0, depth });
|
||||
chessTemp.command(child->move);
|
||||
value = alphaBetaPruning(depth - 1, alpha, beta, child);
|
||||
chessTemp.data = hashTable.back().data;
|
||||
hashTable.pop_back();
|
||||
// 取最小值
|
||||
if (value < beta)
|
||||
beta = value;
|
||||
|
@ -116,6 +279,45 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
|
|||
return node->value;
|
||||
}
|
||||
|
||||
const char *NineChessAi_ab::bestMove()
|
||||
{
|
||||
if ((rootNode->children).size() == 0)
|
||||
return "error!";
|
||||
// 在最好的招法中随机挑一个
|
||||
int16_t moves[12] = {0};
|
||||
int n = 0;
|
||||
for (auto child : rootNode->children) {
|
||||
if (child->value == rootNode->value)
|
||||
moves[n++] = child->move;
|
||||
if (n >= 12)
|
||||
break;
|
||||
}
|
||||
srand((unsigned)time(0));
|
||||
int i = rand() % 12;
|
||||
return move2string(moves[i]);
|
||||
}
|
||||
|
||||
const char *NineChessAi_ab::move2string(int16_t move)
|
||||
{
|
||||
int c, p;
|
||||
if (move < 0) {
|
||||
chessTemp.pos2cp(-move, c, p);
|
||||
sprintf(cmdline, "-(%1u,%1u)", c, p);
|
||||
}
|
||||
else if (move & 0x00ff) {
|
||||
chessTemp.pos2cp(move & 0x00ff, c, p);
|
||||
sprintf(cmdline, "(%1u,%1u)", c, p);
|
||||
}
|
||||
else {
|
||||
int c1, p1;
|
||||
chessTemp.pos2cp(move >> 8, c1, p1);
|
||||
chessTemp.pos2cp(move & 0x00ff, c, p);
|
||||
sprintf(cmdline, "(%1u,%1u)->(%1u,%1u)", c1, p1, c, p);
|
||||
}
|
||||
return cmdline;
|
||||
}
|
||||
|
||||
|
||||
void NineChessAi_ab::reverse(const NineChess *node1, NineChess *node2, int i)
|
||||
{
|
||||
|
||||
|
@ -131,12 +333,13 @@ void NineChessAi_ab::rotate(const NineChess *node1, NineChess *node2, int i)
|
|||
|
||||
}
|
||||
|
||||
bool NineChessAi_ab::isInCache(Node * node, int &value)
|
||||
bool NineChessAi_ab::isInHash(const Node *node)
|
||||
{
|
||||
/* NineChess tempData;
|
||||
/*
|
||||
NineChess tempData;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
reverse(node, &tempData, i);
|
||||
for (int j = 0; j < 6; j++) {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
turn(node, &tempData, j);
|
||||
int n = chess.rule.hasX ? 8 : 4;
|
||||
for (int k = 0; k < n; k++) {
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
#ifndef NINECHESSAI_AB
|
||||
/****************************************************************************
|
||||
** by liuweilhy, 2018.11.29
|
||||
** Mail: liuweilhy@163.com
|
||||
** This file is part of the NineChess game.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef NINECHESSAI_AB
|
||||
#define NINECHESSAI_AB
|
||||
|
||||
#include "ninechess.h"
|
||||
|
@ -6,15 +12,24 @@
|
|||
|
||||
// 注意:NineChess类不是线程安全的!
|
||||
// 所以不能在ai类中修改NineChess类的静态成员变量,切记!
|
||||
|
||||
// 另外,AI类是NineChess类的友元类,可以访问其私有变量
|
||||
// 尽量不要使用NineChess的操作函数,因为有参数安全性检测和不必要的赋值,影响效率
|
||||
|
||||
class NineChessAi_ab
|
||||
{
|
||||
public:
|
||||
// 定义哈希表
|
||||
struct Hash{
|
||||
NineChess::ChessData data;
|
||||
uint64_t value;
|
||||
int depth;
|
||||
};
|
||||
|
||||
// 定义一个节点结构体
|
||||
struct Node{
|
||||
struct Node {
|
||||
uint64_t hash; // 当前局面的哈希值
|
||||
int value; // 节点的值
|
||||
short move_; // 招法的命令行指令,图上标示为节点前的连线
|
||||
int16_t move; // 招法的命令行指令,图上标示为节点前的连线
|
||||
struct Node * parent; // 父节点
|
||||
list<struct Node *> children; // 子节点列表
|
||||
};
|
||||
|
@ -26,6 +41,10 @@ public:
|
|||
void setChess(const NineChess &chess);
|
||||
void setDepth(int depth) { this->depth = depth; }
|
||||
void quit() { requiredQuit = true; }
|
||||
// Alpha-Beta剪枝算法
|
||||
int alphaBetaPruning(int depth);
|
||||
// 返回最佳走法的命令行
|
||||
const char *bestMove();
|
||||
|
||||
protected:
|
||||
// 建立子节点
|
||||
|
@ -38,6 +57,8 @@ protected:
|
|||
int evaluate(Node *node);
|
||||
// Alpha-Beta剪枝算法
|
||||
int alphaBetaPruning(int depth, int alpha, int beta, Node *node);
|
||||
// 返回招法的命令行
|
||||
const char *move2string(int16_t move);
|
||||
|
||||
// 局面逆序
|
||||
void reverse(const NineChess *node1, NineChess *node2, int i);
|
||||
|
@ -45,28 +66,36 @@ protected:
|
|||
void turn(const NineChess *node1, NineChess *node2, int i);
|
||||
// 局面旋转
|
||||
void rotate(const NineChess *node1, NineChess *node2, int i);
|
||||
// 判断是否在缓存中
|
||||
bool isInCache(Node * node, int &value);
|
||||
|
||||
// 判断是否在哈希表中
|
||||
bool isInHash(const Node *node);
|
||||
|
||||
private:
|
||||
// 原始模型
|
||||
NineChess chess;
|
||||
// 演算用的模型
|
||||
NineChess chessTemp;
|
||||
NineChess::ChessData *chessData;
|
||||
|
||||
// 根节点
|
||||
Node * rootNode;
|
||||
// 局面数据缓存区
|
||||
list<NineChess> dataCache;
|
||||
// 局面数据缓存区最大大小
|
||||
size_t cacheMaxSize;
|
||||
// 局面数据哈希表
|
||||
list<struct Hash> hashTable;
|
||||
// 哈希表最大大小
|
||||
size_t hashTableMaxSize;
|
||||
|
||||
// 标识,用于跳出剪枝算法,立即返回
|
||||
bool requiredQuit;
|
||||
// 剪枝算法的层深
|
||||
int depth;
|
||||
// 定义极大值,等于32位有符号整形数字的最大值
|
||||
static const int infinity = 0x7fffffff;
|
||||
static const int infinity = INT32_MAX;
|
||||
|
||||
private:
|
||||
// 棋子价值表
|
||||
char boardScore[(NineChess::RING + 2)*NineChess::SEAT];
|
||||
// 命令行
|
||||
char cmdline[32];
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
113
范例棋谱.txt
113
范例棋谱.txt
|
@ -1,50 +1,69 @@
|
|||
r3 s000 t00
|
||||
(3,1) 00:00.000
|
||||
(2,1) 00:01.390
|
||||
(2,3) 00:01.701
|
||||
(2,4) 00:03.027
|
||||
(3,2) 00:04.404
|
||||
(2,2) 00:04.111
|
||||
(3,8) 00:06.017
|
||||
-(2,1) 00:08.355
|
||||
(2,8) 00:09.284
|
||||
(1,1) 00:10.028
|
||||
(2,1) 00:10.625
|
||||
-(1,1) 00:11.837
|
||||
(1,4) 00:14.877
|
||||
(1,3) 00:18.100
|
||||
(3,3) 00:17.331
|
||||
(3,4) 00:19.044
|
||||
(3,5) 00:19.068
|
||||
(2,5) 00:21.019
|
||||
(1,5) 00:20.360
|
||||
(2,7) 00:24.118
|
||||
(1,5)->(1,6) 00:22.927
|
||||
(2,5)->(2,6) 00:25.459
|
||||
-(3,5) 00:28.499
|
||||
(1,6)->(1,5) 00:25.352
|
||||
(2,6)->(2,5) 00:30.155
|
||||
(1,5)->(1,6) 00:26.503
|
||||
(2,7)->(2,6) 00:31.620
|
||||
-(1,6) 00:32.290
|
||||
(1,4)->(1,5) 00:28.604
|
||||
(2,8)->(2,7) 00:34.556
|
||||
(3,8)->(3,7) 00:30.648
|
||||
(2,1)->(2,8) 00:36.458
|
||||
-(3,1) 00:39.850
|
||||
(3,2)->(3,1) 00:34.675
|
||||
(2,5)->(3,5) 00:46.946
|
||||
(1,5)->(1,4) 00:36.227
|
||||
(2,6)->(2,5) 00:48.337
|
||||
(3,7)->(3,8) 00:38.581
|
||||
(2,7)->(2,6) 00:50.010
|
||||
-(3,3) 00:51.016
|
||||
(2,3)->(3,3) 00:43.433
|
||||
(1,3)->(2,3) 00:52.296
|
||||
-(3,3) 00:52.822
|
||||
(1,4)->(1,3) 00:45.444
|
||||
(2,5)->(1,5) 00:56.716
|
||||
(1,3)->(1,2) 00:46.681
|
||||
(2,4)->(2,5) 00:59.099
|
||||
-(1,2) 01:60.821
|
||||
(2,2) 00:00.862
|
||||
(3,8) 00:00.933
|
||||
(2,1) 00:01.718
|
||||
(3,2) 00:01.902
|
||||
-(2,2) 00:02.860
|
||||
(2,2) 00:02.931
|
||||
(2,3) 00:03.797
|
||||
(2,8) 00:04.163
|
||||
-(2,3) 00:08.181
|
||||
(3,3) 00:05.117
|
||||
(1,2) 00:08.978
|
||||
(3,4) 00:06.070
|
||||
-(1,2) 00:09.135
|
||||
(2,4) 00:11.820
|
||||
(1,3) 00:12.683
|
||||
(2,3) 00:12.638
|
||||
-(1,3) 00:13.435
|
||||
(1,2) 00:15.614
|
||||
(1,3) 00:14.292
|
||||
(1,1) 00:18.783
|
||||
(1,7) 00:16.909
|
||||
(1,1)->(1,8) 00:25.186
|
||||
(1,7)->(1,6) 00:18.661
|
||||
(1,8)->(1,1) 00:27.009
|
||||
(1,3)->(1,4) 00:21.829
|
||||
(1,2)->(1,3) 00:29.741
|
||||
(2,4)->(2,5) 00:23.310
|
||||
(1,3)->(1,2) 00:31.160
|
||||
(2,5)->(1,5) 00:25.351
|
||||
-(1,1) 00:26.217
|
||||
(1,2)->(1,1) 00:34.764
|
||||
(1,5)->(2,5) 00:28.847
|
||||
(1,1)->(1,2) 00:36.665
|
||||
(2,5)->(3,5) 00:30.555
|
||||
(1,2)->(1,3) 00:43.333
|
||||
(1,6)->(1,5) 00:31.964
|
||||
(1,3)->(1,2) 00:45.544
|
||||
(1,5)->(2,5) 00:33.201
|
||||
(1,2)->(1,3) 00:48.734
|
||||
(1,4)->(1,5) 00:34.476
|
||||
-(1,3) 00:35.306
|
||||
(3,8)->(3,7) 00:56.347
|
||||
(2,5)->(2,6) 00:37.406
|
||||
(3,7)->(3,8) 00:58.193
|
||||
(3,5)->(2,5) 00:39.694
|
||||
(3,8)->(3,7) 01:61.938
|
||||
(1,5)->(1,4) 00:41.361
|
||||
(3,7)->(3,8) 01:63.645
|
||||
(2,3)->(2,4) 00:43.490
|
||||
-(3,2) 00:46.140
|
||||
(3,3)->(3,2) 01:70.759
|
||||
-(1,4) 01:72.136
|
||||
(2,2)->(2,3) 00:47.966
|
||||
(3,2)->(3,3) 01:73.383
|
||||
(2,3)->(2,2) 00:50.108
|
||||
(3,1)->(3,2) 01:75.424
|
||||
-(2,2) 01:76.448
|
||||
(2,4)->(2,3) 00:55.468
|
||||
(3,8)->(3,1) 01:78.611
|
||||
(2,3)->(2,2) 00:57.257
|
||||
-(3,1) 00:58.015
|
||||
(3,3)->(2,3) 01:84.964
|
||||
(2,8)->(2,7) 00:59.896
|
||||
(2,3)->(3,3) 01:86.208
|
||||
(2,1)->(2,8) 01:61.493
|
||||
-(3,2) 01:62.658
|
||||
Player2 win!
|
||||
|
|
Loading…
Reference in New Issue