AI与GUI交互逻辑优化
This commit is contained in:
parent
76da5d3527
commit
3d36cefa8d
|
@ -48,7 +48,7 @@ void AiThread::run()
|
|||
mutex.unlock();
|
||||
}
|
||||
|
||||
ai_ab.alphaBetaPruning(3);
|
||||
ai_ab.alphaBetaPruning(6);
|
||||
const char * str = ai_ab.bestMove();
|
||||
qDebug() << str;
|
||||
if (strcmp(str, "error!"))
|
||||
|
|
|
@ -334,89 +334,22 @@ void GameController::timerEvent(QTimerEvent *event)
|
|||
*/
|
||||
}
|
||||
|
||||
bool GameController::command(const QString &cmd, bool update /*= true*/)
|
||||
{
|
||||
// 防止接收滞后结束的线程发送的指令
|
||||
if (sender() == &ai1 && !isEngine1)
|
||||
return false;
|
||||
if (sender() == &ai2 && !isEngine2)
|
||||
return false;
|
||||
|
||||
if (!chess.command(cmd.toStdString().c_str()))
|
||||
return false;
|
||||
|
||||
if (chess.getPhase() == NineChess::GAME_NOTSTARTED) {
|
||||
gameReset();
|
||||
gameStart();
|
||||
}
|
||||
|
||||
if (update)
|
||||
updateScence(chess);
|
||||
|
||||
// 将新增的棋谱行插入到ListModel
|
||||
currentRow = manualListModel.rowCount() - 1;
|
||||
int k = 0;
|
||||
// 输出命令行
|
||||
for (auto i = (chess.getCmdList())->begin(); i != (chess.getCmdList())->end(); ++i) {
|
||||
// 跳过已添加的,因标准list容器没有下标
|
||||
if (k++ <= currentRow)
|
||||
continue;
|
||||
manualListModel.insertRow(++currentRow);
|
||||
manualListModel.setData(manualListModel.index(currentRow), (*i).c_str());
|
||||
}
|
||||
|
||||
// AI设置
|
||||
if (&chess == &(this->chess)) {
|
||||
// 如果还未决出胜负
|
||||
if (chess.whoWin() == NineChess::NOBODY) {
|
||||
if (chess.whosTurn() == NineChess::PLAYER1) {
|
||||
if (isEngine1)
|
||||
ai1.resume();
|
||||
}
|
||||
else {
|
||||
if (isEngine2)
|
||||
ai2.resume();
|
||||
}
|
||||
}
|
||||
// 如果已经决出胜负
|
||||
else {
|
||||
ai1.stop();
|
||||
ai2.stop();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 历史局面
|
||||
bool GameController::phaseChange(int row)
|
||||
{
|
||||
// 如果row是当前浏览的棋谱行,则不需要刷新
|
||||
if (currentRow == row)
|
||||
return false;
|
||||
|
||||
// 需要刷新
|
||||
currentRow = row;
|
||||
int rows = manualListModel.rowCount();
|
||||
QStringList mlist = manualListModel.stringList();
|
||||
qDebug() << "rows:" << rows << " current:" << row;
|
||||
for (int i = 0; i <= row; i++)
|
||||
{
|
||||
qDebug() << mlist.at(i);
|
||||
chessTemp.command(mlist.at(i).toStdString().c_str());
|
||||
}
|
||||
// 下面这步关键,会让悔棋者承担时间损失
|
||||
chessTemp.setStartTimeb(chess.getStartTimeb());
|
||||
// 刷新棋局场景
|
||||
updateScence(chessTemp);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 槽函数,根据QGraphicsScene的信号和状态来执行选子、落子或去子
|
||||
bool GameController::actionPiece(QPointF pos)
|
||||
{
|
||||
bool result = false;
|
||||
// 点击非落子点,不执行
|
||||
int c, p;
|
||||
if (!scene.pos2cp(pos, c, p)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 是否在浏览历史记录
|
||||
// 电脑走棋时,点击无效
|
||||
if (chess.whosTurn() == NineChess::PLAYER1 && isEngine1)
|
||||
return false;
|
||||
if (chess.whosTurn() == NineChess::PLAYER2 && isEngine2)
|
||||
return false;
|
||||
|
||||
// 在浏览历史记录时点击棋盘,则认为是悔棋
|
||||
if (currentRow != manualListModel.rowCount() - 1)
|
||||
{
|
||||
// 定义新对话框
|
||||
|
@ -444,39 +377,60 @@ bool GameController::actionPiece(QPointF pos)
|
|||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return result;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
switch (chess.getPhase()) {
|
||||
case NineChess::GAME_NOTSTARTED:
|
||||
// 如果未开局则开局,这里还要继续判断,不可break
|
||||
// 如果未开局则开局
|
||||
if (chess.getPhase() == NineChess::GAME_NOTSTARTED)
|
||||
gameStart();
|
||||
|
||||
case NineChess::GAME_OPENING:
|
||||
// 如果是开局阶段(轮流落下新子),落子
|
||||
if (chess.getAction() == NineChess::ACTION_PLACE) {
|
||||
result = placePiece(pos);
|
||||
}// 去子
|
||||
else if (chess.getAction() == NineChess::ACTION_CAPTURE) {
|
||||
result = capturePiece(pos);
|
||||
// 判断执行选子、落子或去子
|
||||
bool result = false;
|
||||
PieceItem *piece = nullptr;
|
||||
QGraphicsItem *item = scene.itemAt(pos, QTransform());
|
||||
|
||||
switch (chess.getAction())
|
||||
{
|
||||
case NineChess::ACTION_PLACE:
|
||||
if (chess.place(c, p))
|
||||
{
|
||||
if (chess.getAction() == NineChess::ACTION_CAPTURE) {
|
||||
// 播放成三音效
|
||||
playSound(":/sound/resources/sound/capture.wav");
|
||||
}
|
||||
else {
|
||||
// 播放移动棋子音效
|
||||
playSound(":/sound/resources/sound/drog.wav");
|
||||
}
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
// 如果移子不成功,尝试重新选子,这里不break
|
||||
|
||||
case NineChess::ACTION_CHOOSE:
|
||||
piece = qgraphicsitem_cast<PieceItem *>(item);
|
||||
if (!piece)
|
||||
break;
|
||||
if (chess.choose(c, p)) {
|
||||
// 播放选子音效
|
||||
playSound(":/sound/resources/sound/choose.wav");
|
||||
result = true;
|
||||
}
|
||||
else {
|
||||
// 播放禁止音效
|
||||
playSound(":/sound/resources/sound/forbidden.wav");
|
||||
}
|
||||
break;
|
||||
|
||||
case NineChess::GAME_MID:
|
||||
// 如果是中局阶段(轮流移子)
|
||||
// 选子
|
||||
if (chess.getAction() == NineChess::ACTION_CHOOSE) {
|
||||
result = choosePiece(pos);
|
||||
}// 移子
|
||||
else if (chess.getAction() == NineChess::ACTION_PLACE) {
|
||||
// 如果移子不成功,尝试重新选子
|
||||
result = movePiece(pos);
|
||||
}// 去子
|
||||
else if (chess.getAction() == NineChess::ACTION_CAPTURE) {
|
||||
result = capturePiece(pos);
|
||||
case NineChess::ACTION_CAPTURE:
|
||||
if (chess.capture(c, p)) {
|
||||
// 播放音效
|
||||
playSound(":/sound/resources/sound/remove.wav");
|
||||
result = true;
|
||||
}
|
||||
else {
|
||||
// 播放禁止音效
|
||||
playSound(":/sound/resources/sound/forbidden.wav");
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -487,6 +441,10 @@ bool GameController::actionPiece(QPointF pos)
|
|||
|
||||
if (result)
|
||||
{
|
||||
// 发信号更新状态栏
|
||||
message = QString::fromStdString(chess.getTip());
|
||||
emit statusBarChanged(message);
|
||||
|
||||
// 将新增的棋谱行插入到ListModel
|
||||
currentRow = manualListModel.rowCount() - 1;
|
||||
int k = 0;
|
||||
|
@ -498,116 +456,142 @@ bool GameController::actionPiece(QPointF pos)
|
|||
manualListModel.insertRow(++currentRow);
|
||||
manualListModel.setData(manualListModel.index(currentRow), (*i).c_str());
|
||||
}
|
||||
if (chess.whoWin() != NineChess::NOBODY &&
|
||||
(manualListModel.data(manualListModel.index(currentRow-1))).toString().contains("Time over."))
|
||||
if (chess.whoWin() != NineChess::NOBODY &&
|
||||
(manualListModel.data(manualListModel.index(currentRow - 1))).toString().contains("Time over."))
|
||||
playSound(":/sound/resources/sound/win.wav");
|
||||
|
||||
// AI设置
|
||||
if (&chess == &(this->chess)) {
|
||||
// 如果还未决出胜负
|
||||
if (chess.whoWin() == NineChess::NOBODY) {
|
||||
if (chess.whosTurn() == NineChess::PLAYER1) {
|
||||
if (isEngine1)
|
||||
ai1.resume();
|
||||
if (isEngine2)
|
||||
ai2.pause();
|
||||
}
|
||||
else {
|
||||
if (isEngine1)
|
||||
ai1.pause();
|
||||
if (isEngine2)
|
||||
ai2.resume();
|
||||
}
|
||||
}
|
||||
// 如果已经决出胜负
|
||||
else {
|
||||
ai1.stop();
|
||||
ai2.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateScence();
|
||||
return result;
|
||||
}
|
||||
|
||||
// 选子
|
||||
bool GameController::choosePiece(QPointF pos)
|
||||
// 棋谱的命令行执行
|
||||
bool GameController::command(const QString &cmd, bool update /*= true*/)
|
||||
{
|
||||
int c, p;
|
||||
if (!scene.pos2cp(pos, c, p)) {
|
||||
return false;
|
||||
}
|
||||
PieceItem *piece = nullptr;
|
||||
QGraphicsItem *item = scene.itemAt(pos, QTransform());
|
||||
piece = qgraphicsitem_cast<PieceItem *>(item);
|
||||
if (!piece) {
|
||||
return false;
|
||||
}
|
||||
if (chess.choose(c, p)) {
|
||||
// 发信号更新状态栏
|
||||
message = QString::fromStdString(chess.getTip());
|
||||
emit statusBarChanged(message);
|
||||
// 播放选子音效
|
||||
playSound(":/sound/resources/sound/choose.wav");
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
// 播放禁止音效
|
||||
playSound(":/sound/resources/sound/forbidden.wav");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Q_UNUSED(hasSound)
|
||||
|
||||
// 落下新子
|
||||
bool GameController::placePiece(QPointF pos)
|
||||
{
|
||||
int c, p;
|
||||
if (!scene.pos2cp(pos, c, p)) {
|
||||
// 防止接收滞后结束的线程发送的指令
|
||||
if (sender() == &ai1 && !isEngine1)
|
||||
return false;
|
||||
}
|
||||
if (!chess.place(c, p)) {
|
||||
// 播放禁止音效
|
||||
playSound(":/sound/resources/sound/forbidden.wav");
|
||||
if (sender() == &ai2 && !isEngine2)
|
||||
return false;
|
||||
|
||||
// 声音
|
||||
QString sound;
|
||||
switch (chess.getAction())
|
||||
{
|
||||
case NineChess::ACTION_CHOOSE:
|
||||
case NineChess::ACTION_PLACE:
|
||||
sound = ":/sound/resources/sound/drog.wav";
|
||||
break;
|
||||
case NineChess::ACTION_CAPTURE:
|
||||
sound = ":/sound/resources/sound/remove.wav";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!chess.command(cmd.toStdString().c_str()))
|
||||
return false;
|
||||
|
||||
if (sound == ":/sound/resources/sound/drog.wav" && chess.getAction() == NineChess::ACTION_CAPTURE)
|
||||
{
|
||||
sound = ":/sound/resources/sound/capture.wav";
|
||||
}
|
||||
|
||||
if (chess.getPhase() == NineChess::GAME_NOTSTARTED) {
|
||||
gameReset();
|
||||
gameStart();
|
||||
}
|
||||
|
||||
if (update) {
|
||||
playSound(sound);
|
||||
updateScence(chess);
|
||||
}
|
||||
|
||||
// 将新增的棋谱行插入到ListModel
|
||||
currentRow = manualListModel.rowCount() - 1;
|
||||
int k = 0;
|
||||
// 输出命令行
|
||||
for (auto i = (chess.getCmdList())->begin(); i != (chess.getCmdList())->end(); ++i) {
|
||||
// 跳过已添加的,因标准list容器没有下标
|
||||
if (k++ <= currentRow)
|
||||
continue;
|
||||
manualListModel.insertRow(++currentRow);
|
||||
manualListModel.setData(manualListModel.index(currentRow), (*i).c_str());
|
||||
}
|
||||
|
||||
// AI设置
|
||||
if (&chess == &(this->chess)) {
|
||||
// 如果还未决出胜负
|
||||
if (chess.whoWin() == NineChess::NOBODY) {
|
||||
if (chess.whosTurn() == NineChess::PLAYER1) {
|
||||
if (isEngine1)
|
||||
ai1.resume();
|
||||
if (isEngine2)
|
||||
ai2.pause();
|
||||
}
|
||||
else {
|
||||
if (isEngine1)
|
||||
ai1.pause();
|
||||
if (isEngine2)
|
||||
ai2.resume();
|
||||
}
|
||||
}
|
||||
// 如果已经决出胜负
|
||||
else {
|
||||
ai1.stop();
|
||||
ai2.stop();
|
||||
}
|
||||
}
|
||||
// 发信号更新状态栏
|
||||
message = QString::fromStdString(chess.getTip());
|
||||
emit statusBarChanged(message);
|
||||
// 播放成三音效
|
||||
if (chess.getAction() == NineChess::ACTION_CAPTURE)
|
||||
playSound(":/sound/resources/sound/capture.wav");
|
||||
// 播放落下棋子音效
|
||||
else
|
||||
playSound(":/sound/resources/sound/drog.wav");
|
||||
return true;
|
||||
}
|
||||
|
||||
// 移动旧子
|
||||
bool GameController::movePiece(QPointF pos)
|
||||
// 浏览历史局面,通过command函数刷新局面显示
|
||||
bool GameController::phaseChange(int row)
|
||||
{
|
||||
if (!currentPiece) {
|
||||
// 如果row是当前浏览的棋谱行,则不需要刷新
|
||||
if (currentRow == row)
|
||||
return false;
|
||||
}
|
||||
int c, p;
|
||||
if (!scene.pos2cp(pos, c, p)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (chess.place(c, p))
|
||||
// 需要刷新
|
||||
currentRow = row;
|
||||
int rows = manualListModel.rowCount();
|
||||
QStringList mlist = manualListModel.stringList();
|
||||
qDebug() << "rows:" << rows << " current:" << row;
|
||||
for (int i = 0; i <= row; i++)
|
||||
{
|
||||
// 发信号更新状态栏
|
||||
message = QString::fromStdString(chess.getTip());
|
||||
emit statusBarChanged(message);
|
||||
// 播放成三音效
|
||||
if (chess.getAction() == NineChess::ACTION_CAPTURE)
|
||||
playSound(":/sound/resources/sound/capture.wav");
|
||||
// 播放移动棋子音效
|
||||
else
|
||||
playSound(":/sound/resources/sound/move.wav");
|
||||
return true;
|
||||
qDebug() << mlist.at(i);
|
||||
chessTemp.command(mlist.at(i).toStdString().c_str());
|
||||
}
|
||||
// 如果移子不成功,尝试重新选子
|
||||
else
|
||||
{
|
||||
return choosePiece(pos);
|
||||
}
|
||||
}
|
||||
|
||||
// 去子
|
||||
bool GameController::capturePiece(QPointF pos)
|
||||
{
|
||||
int c, p;
|
||||
if (!scene.pos2cp(pos, c, p)) {
|
||||
return false;
|
||||
}
|
||||
if (!chess.capture(c, p)) {
|
||||
// 播放禁止音效
|
||||
playSound(":/sound/resources/sound/forbidden.wav");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 发信号更新状态栏
|
||||
message = QString::fromStdString(chess.getTip());
|
||||
emit statusBarChanged(message);
|
||||
// 播放音效
|
||||
playSound(":/sound/resources/sound/remove.wav");
|
||||
// 下面这步关键,会让悔棋者承担时间损失
|
||||
chessTemp.setStartTimeb(chess.getStartTimeb());
|
||||
// 刷新棋局场景
|
||||
updateScence(chessTemp);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ public slots:
|
|||
bool command(const QString &cmd, bool update = true);
|
||||
// 历史局面及局面改变
|
||||
bool phaseChange(int row);
|
||||
// 更新棋局显示,每步后必须执行
|
||||
// 更新棋局显示,每步后执行才能刷新局面
|
||||
bool updateScence();
|
||||
bool updateScence(NineChess &chess);
|
||||
|
||||
|
@ -83,14 +83,6 @@ protected:
|
|||
//bool eventFilter(QObject * watched, QEvent * event);
|
||||
// 定时器
|
||||
void timerEvent(QTimerEvent * event);
|
||||
// 选子
|
||||
bool choosePiece(QPointF pos);
|
||||
// 落下新子
|
||||
bool placePiece(QPointF pos);
|
||||
// 移动旧子
|
||||
bool movePiece(QPointF pos);
|
||||
// 去子
|
||||
bool capturePiece(QPointF pos);
|
||||
|
||||
private:
|
||||
// 棋对象的数据模型
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include "ninechessai_ab.h"
|
||||
#include <cmath>
|
||||
#include <time.h>
|
||||
#include <qdebug.h>
|
||||
|
||||
NineChessAi_ab::NineChessAi_ab():
|
||||
rootNode(nullptr),
|
||||
|
@ -156,28 +155,6 @@ void NineChessAi_ab::setChess(const NineChess &chess)
|
|||
rootNode->parent = nullptr;
|
||||
|
||||
requiredQuit = false;
|
||||
// 生成棋子价值表
|
||||
for (int j = 0; j < NineChess::SEAT; j++)
|
||||
{
|
||||
// 对于0、2、4、6位(偶数位)
|
||||
if (!(j & 1)) {
|
||||
boardScore[1 * NineChess::SEAT + j] = 90;
|
||||
boardScore[2 * NineChess::SEAT + j] = 100;
|
||||
boardScore[3 * NineChess::SEAT + j] = 90;
|
||||
}
|
||||
// 对于有斜线情况下的1、3、5、7位(奇数位)
|
||||
else if(chessTemp.rule.hasObliqueLine) {
|
||||
boardScore[1 * NineChess::SEAT + j] = 85;
|
||||
boardScore[2 * NineChess::SEAT + j] = 95;
|
||||
boardScore[3 * NineChess::SEAT + j] = 85;
|
||||
}
|
||||
// 对于无斜线情况下的1、3、5、7位(奇数位)
|
||||
else {
|
||||
boardScore[1 * NineChess::SEAT + j] = 80;
|
||||
boardScore[2 * NineChess::SEAT + j] = 85;
|
||||
boardScore[3 * NineChess::SEAT + j] = 80;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int NineChessAi_ab::evaluate(Node *node)
|
||||
|
@ -189,27 +166,38 @@ int NineChessAi_ab::evaluate(Node *node)
|
|||
case NineChess::GAME_NOTSTARTED:
|
||||
break;
|
||||
|
||||
// 开局和中局阶段用同样的评价方法
|
||||
case NineChess::GAME_OPENING:
|
||||
case NineChess::GAME_MID:
|
||||
// 按手棋数目计分,每子50分
|
||||
value += (chessData->player1_InHand) * 50 - (chessData->player2_InHand) * 50;
|
||||
// 按手中的棋子计分,不要break;
|
||||
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];
|
||||
value += chessData->player1_Remain * 100 - chessData->player2_Remain * 100;
|
||||
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_MID:
|
||||
// 按场上棋子计分
|
||||
value += chessData->player1_Remain * 100 - chessData->player2_Remain * 100;
|
||||
switch (chessData->action)
|
||||
{
|
||||
// 选子和落子使用相同的评价方法
|
||||
case NineChess::ACTION_CHOOSE:
|
||||
case NineChess::ACTION_PLACE:
|
||||
break;
|
||||
// 如果形成去子状态,每有一个可去的子,算1000分
|
||||
// 如果形成去子状态,每有一个可去的子,算100分
|
||||
case NineChess::ACTION_CAPTURE:
|
||||
value += (chessData->turn == NineChess::PLAYER1) ? chessData->num_NeedRemove * 1000 : -chessData->num_NeedRemove * 1000;
|
||||
value += (chessData->turn == NineChess::PLAYER1) ? (chessData->num_NeedRemove) * 100 : -(chessData->num_NeedRemove) * 100;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -242,6 +230,9 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
|
|||
{
|
||||
// 评价值
|
||||
int value;
|
||||
// 当前节点的MinMax值,最终赋值给节点value,与alpha和Beta不同
|
||||
int minMax;
|
||||
|
||||
if (!depth || chessTemp.data.phase == NineChess::GAME_OVER) {
|
||||
node->value = evaluate(node);
|
||||
return node->value;
|
||||
|
@ -255,45 +246,45 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
|
|||
// 根据演算模型执行MiniMax检索
|
||||
// 对先手,搜索Max
|
||||
if (chessTemp.whosTurn() == NineChess::PLAYER1) {
|
||||
minMax = -infinity;
|
||||
for (auto child : node->children) {
|
||||
dataStack.push(chessTemp.data);
|
||||
if(!chessTemp.command(child->move))
|
||||
qDebug() << child->move;
|
||||
chessTemp.command(child->move);
|
||||
value = alphaBetaPruning(depth - 1, alpha, beta, child);
|
||||
chessTemp.data = dataStack.top();
|
||||
dataStack.pop();
|
||||
// 取最大值
|
||||
if (value > minMax)
|
||||
minMax = value;
|
||||
if (value > alpha)
|
||||
alpha = value;
|
||||
// 剪枝返回
|
||||
if (alpha >= beta) {
|
||||
node->value = alpha;
|
||||
return value;
|
||||
}
|
||||
if (alpha >= beta)
|
||||
break;
|
||||
}
|
||||
// 取最大值
|
||||
node->value = alpha;
|
||||
node->value = minMax;
|
||||
}
|
||||
// 对后手,搜索Min
|
||||
else {
|
||||
minMax = infinity;
|
||||
for (auto child : node->children) {
|
||||
dataStack.push(chessTemp.data);
|
||||
if(!chessTemp.command(child->move))
|
||||
qDebug() << child->move;
|
||||
chessTemp.command(child->move);
|
||||
value = alphaBetaPruning(depth - 1, alpha, beta, child);
|
||||
chessTemp.data = dataStack.top();
|
||||
dataStack.pop();
|
||||
// 取最小值
|
||||
if (value < minMax)
|
||||
minMax = value;
|
||||
if (value < beta)
|
||||
beta = value;
|
||||
// 剪枝返回
|
||||
if (alpha >= beta) {
|
||||
node->value = beta;
|
||||
return value;
|
||||
}
|
||||
if (alpha >= beta)
|
||||
break;
|
||||
}
|
||||
// 取最小值
|
||||
node->value = beta;
|
||||
node->value = minMax;
|
||||
}
|
||||
// 返回
|
||||
return node->value;
|
||||
|
@ -303,18 +294,11 @@ 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;
|
||||
return move2string(child->move);
|
||||
}
|
||||
srand((unsigned)time(0));
|
||||
int i = rand() % n;
|
||||
return move2string(moves[i]);
|
||||
return "error!";
|
||||
}
|
||||
|
||||
const char *NineChessAi_ab::move2string(int16_t move)
|
||||
|
|
|
@ -97,8 +97,6 @@ private:
|
|||
static const int infinity = INT32_MAX;
|
||||
|
||||
private:
|
||||
// 棋子价值表
|
||||
char boardScore[(NineChess::RING + 2)*NineChess::SEAT];
|
||||
// 命令行
|
||||
char cmdline[32];
|
||||
};
|
||||
|
|
|
@ -27,7 +27,8 @@ NineChessWindow::NineChessWindow(QWidget *parent)
|
|||
: QMainWindow(parent),
|
||||
scene(nullptr),
|
||||
game(nullptr),
|
||||
ruleNo(-1)
|
||||
ruleNo(-1),
|
||||
autoRunTimer(this)
|
||||
{
|
||||
ui.setupUi(this);
|
||||
//去掉标题栏
|
||||
|
@ -73,10 +74,14 @@ NineChessWindow::NineChessWindow(QWidget *parent)
|
|||
// 初始化游戏规则菜单
|
||||
ui.menu_R->installEventFilter(this);
|
||||
|
||||
// 关联自动运行定时器
|
||||
connect(&autoRunTimer, SIGNAL(timeout()),
|
||||
this, SLOT(onAutoRunTimeOut()));
|
||||
|
||||
// 主窗口居中显示
|
||||
QRect deskTopRect = qApp->desktop()->availableGeometry();
|
||||
int unitw=(deskTopRect.width() - width())/2;
|
||||
int unith=(deskTopRect.height() - height())/2;
|
||||
int unitw = (deskTopRect.width() - width())/2;
|
||||
int unith = (deskTopRect.height() - height())/2;
|
||||
this->move(unitw,unith);
|
||||
|
||||
// 游戏初始化
|
||||
|
@ -96,6 +101,8 @@ void NineChessWindow::closeEvent(QCloseEvent *event)
|
|||
{
|
||||
if (file.isOpen())
|
||||
file.close();
|
||||
// 取消自动运行
|
||||
ui.actionAutoRun_A->setChecked(false);
|
||||
//qDebug() << "closed";
|
||||
QMainWindow::closeEvent(event);
|
||||
}
|
||||
|
@ -310,9 +317,13 @@ void NineChessWindow::on_actionLimited_T_triggered()
|
|||
|
||||
void NineChessWindow::actionRules_triggered()
|
||||
{
|
||||
// 取消自动运行
|
||||
ui.actionAutoRun_A->setChecked(false);
|
||||
|
||||
// 取消其它规则的选择
|
||||
for(QAction *action: ruleActionList)
|
||||
action->setChecked(false);
|
||||
|
||||
// 选择当前规则
|
||||
QAction *action = dynamic_cast<QAction *>(sender());
|
||||
action->setChecked(true);
|
||||
|
@ -336,6 +347,8 @@ void NineChessWindow::on_actionNew_N_triggered()
|
|||
{
|
||||
if (file.isOpen())
|
||||
file.close();
|
||||
// 取消自动运行
|
||||
ui.actionAutoRun_A->setChecked(false);
|
||||
// 取消AI设定
|
||||
ui.actionEngine1_T->setChecked(false);
|
||||
ui.actionEngine2_R->setChecked(false);
|
||||
|
@ -525,6 +538,10 @@ void NineChessWindow::on_actionRowChange()
|
|||
}
|
||||
}
|
||||
|
||||
// 更新局面
|
||||
game->phaseChange(currentRow);
|
||||
|
||||
/* 下面的代码全部取消,改用QTimer的方式实现
|
||||
// 更新局面
|
||||
bool changed = game->phaseChange(currentRow);
|
||||
// 处理自动播放时的动画
|
||||
|
@ -542,70 +559,77 @@ void NineChessWindow::on_actionRowChange()
|
|||
QTimer::singleShot(waitTime, &loop, SLOT(quit()));
|
||||
loop.exec();
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void NineChessWindow::onAutoRunTimeOut(QPrivateSignal signal)
|
||||
{
|
||||
int rows = ui.listView->model()->rowCount();
|
||||
int currentRow = ui.listView->currentIndex().row();
|
||||
|
||||
if (rows <= 1) {
|
||||
ui.actionAutoRun_A->setChecked(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// 执行“下一招”
|
||||
if (currentRow < rows - 1)
|
||||
{
|
||||
if (currentRow < rows - 1)
|
||||
{
|
||||
ui.listView->setCurrentIndex(ui.listView->model()->index(currentRow + 1, 0));
|
||||
}
|
||||
currentRow = ui.listView->currentIndex().row();
|
||||
// 更新动作状态
|
||||
if (currentRow <= 0) {
|
||||
ui.actionBegin_S->setEnabled(false);
|
||||
ui.actionPrevious_B->setEnabled(false);
|
||||
ui.actionNext_F->setEnabled(true);
|
||||
ui.actionEnd_E->setEnabled(true);
|
||||
ui.actionAutoRun_A->setEnabled(true);
|
||||
}
|
||||
else if (currentRow >= rows - 1)
|
||||
{
|
||||
ui.actionBegin_S->setEnabled(true);
|
||||
ui.actionPrevious_B->setEnabled(true);
|
||||
ui.actionNext_F->setEnabled(false);
|
||||
ui.actionEnd_E->setEnabled(false);
|
||||
ui.actionAutoRun_A->setEnabled(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui.actionBegin_S->setEnabled(true);
|
||||
ui.actionPrevious_B->setEnabled(true);
|
||||
ui.actionNext_F->setEnabled(true);
|
||||
ui.actionEnd_E->setEnabled(true);
|
||||
ui.actionAutoRun_A->setEnabled(true);
|
||||
}
|
||||
|
||||
// 更新局面
|
||||
game->phaseChange(currentRow);
|
||||
}
|
||||
else {
|
||||
ui.actionAutoRun_A->setChecked(false);
|
||||
}
|
||||
}
|
||||
|
||||
// 自动运行
|
||||
void NineChessWindow::on_actionAutoRun_A_toggled(bool arg1)
|
||||
{
|
||||
if (!arg1)
|
||||
return;
|
||||
|
||||
int rows = ui.listView->model()->rowCount();
|
||||
int currentRow = ui.listView->currentIndex().row();
|
||||
|
||||
if (rows <= 1)
|
||||
return;
|
||||
|
||||
// 自动运行前禁用所有控件
|
||||
ui.menuBar->setEnabled(false);
|
||||
ui.mainToolBar->setEnabled(false);
|
||||
ui.dockWidget->setEnabled(false);
|
||||
ui.gameView->setEnabled(false);
|
||||
|
||||
// 反复执行“下一招”
|
||||
while (currentRow < rows - 1)
|
||||
{
|
||||
if (currentRow < rows - 1)
|
||||
{
|
||||
ui.listView->setCurrentIndex(ui.listView->model()->index(currentRow + 1, 0));
|
||||
}
|
||||
currentRow = ui.listView->currentIndex().row();
|
||||
// 更新动作状态
|
||||
if (currentRow <= 0) {
|
||||
ui.actionBegin_S->setEnabled(false);
|
||||
ui.actionPrevious_B->setEnabled(false);
|
||||
ui.actionNext_F->setEnabled(true);
|
||||
ui.actionEnd_E->setEnabled(true);
|
||||
ui.actionAutoRun_A->setEnabled(true);
|
||||
}
|
||||
else if (currentRow >= rows - 1)
|
||||
{
|
||||
ui.actionBegin_S->setEnabled(true);
|
||||
ui.actionPrevious_B->setEnabled(true);
|
||||
ui.actionNext_F->setEnabled(false);
|
||||
ui.actionEnd_E->setEnabled(false);
|
||||
ui.actionAutoRun_A->setEnabled(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui.actionBegin_S->setEnabled(true);
|
||||
ui.actionPrevious_B->setEnabled(true);
|
||||
ui.actionNext_F->setEnabled(true);
|
||||
ui.actionEnd_E->setEnabled(true);
|
||||
ui.actionAutoRun_A->setEnabled(true);
|
||||
}
|
||||
|
||||
// 更新局面
|
||||
game->phaseChange(currentRow);
|
||||
}
|
||||
|
||||
// 自动运行结束后启用所有控件
|
||||
ui.menuBar->setEnabled(true);
|
||||
ui.mainToolBar->setEnabled(true);
|
||||
ui.dockWidget->setEnabled(true);
|
||||
ui.gameView->setEnabled(true);
|
||||
// 取消自动运行按钮的选中状态
|
||||
ui.actionAutoRun_A->setChecked(false);
|
||||
if (arg1) {
|
||||
// 自动运行前禁用控件
|
||||
ui.dockWidget->setEnabled(false);
|
||||
ui.gameView->setEnabled(false);
|
||||
// 启动定时器
|
||||
autoRunTimer.start(game->getDurationTime() + 50);
|
||||
}
|
||||
else {
|
||||
// 关闭定时器
|
||||
autoRunTimer.stop();
|
||||
// 自动运行结束后启用控件
|
||||
ui.dockWidget->setEnabled(true);
|
||||
ui.gameView->setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
void NineChessWindow::on_actionLocal_L_triggered()
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <QTextStream>
|
||||
#include <QStringListModel>
|
||||
#include <QFile>
|
||||
#include <QTimer>
|
||||
#include "ui_ninechesswindow.h"
|
||||
|
||||
class GameScene;
|
||||
|
@ -22,27 +23,16 @@ protected:
|
|||
bool eventFilter(QObject * watched, QEvent * event);
|
||||
void closeEvent(QCloseEvent *event);
|
||||
|
||||
private:
|
||||
// 界面文件
|
||||
Ui::NineChessWindowClass ui;
|
||||
// 视图场景
|
||||
GameScene *scene;
|
||||
// 控制器
|
||||
GameController *game;
|
||||
// 动态增加的菜单栏动作列表
|
||||
QList <QAction *> ruleActionList;
|
||||
// 游戏的规则号,涉及菜单项和对话框,所以要有
|
||||
int ruleNo;
|
||||
// 文件
|
||||
QFile file;
|
||||
// 更新规则标签
|
||||
void ruleInfo();
|
||||
|
||||
private slots:
|
||||
// 初始化
|
||||
void initialize();
|
||||
// 动态增加的菜单栏动作的槽函数
|
||||
void actionRules_triggered();
|
||||
// 更新规则标签
|
||||
void ruleInfo();
|
||||
// 自动运行定时处理函数
|
||||
void onAutoRunTimeOut(QPrivateSignal signal);
|
||||
|
||||
// 下面是各动作的槽函数
|
||||
// 注释掉的是已在UI管理器或主窗口初始化函数中连接好的
|
||||
void on_actionNew_N_triggered();
|
||||
|
@ -74,6 +64,22 @@ private slots:
|
|||
void on_actionViewHelp_V_triggered();
|
||||
void on_actionWeb_W_triggered();
|
||||
void on_actionAbout_A_triggered();
|
||||
|
||||
private:
|
||||
// 界面文件
|
||||
Ui::NineChessWindowClass ui;
|
||||
// 视图场景
|
||||
GameScene *scene;
|
||||
// 控制器
|
||||
GameController *game;
|
||||
// 动态增加的菜单栏动作列表
|
||||
QList <QAction *> ruleActionList;
|
||||
// 游戏的规则号,涉及菜单项和对话框,所以要有
|
||||
int ruleNo;
|
||||
// 文件
|
||||
QFile file;
|
||||
// 定时器
|
||||
QTimer autoRunTimer;
|
||||
};
|
||||
|
||||
#endif // NINECHESSWINDOW_H
|
||||
|
|
Loading…
Reference in New Issue