refactor: 将 _1 和 _2 形式改为数组形式 [1] 和 [2]
This commit is contained in:
parent
01c7c6b12f
commit
2eb0872597
|
@ -27,6 +27,7 @@ SOURCES += \
|
|||
src/ai/tt.cpp \
|
||||
src/base/misc.cpp \
|
||||
src/game/board.cpp \
|
||||
src/game/player.cpp \
|
||||
src/game/position.cpp \
|
||||
src/game/rule.cpp \
|
||||
src/main.cpp \
|
||||
|
@ -59,6 +60,7 @@ HEADERS += \
|
|||
src/ai/search.h \
|
||||
src/ai/zobrist.h \
|
||||
src/game/board.h \
|
||||
src/game/player.h \
|
||||
src/game/position.h \
|
||||
src/game/rule.h \
|
||||
src/game/types.h \
|
||||
|
|
|
@ -87,12 +87,12 @@ value_t Evaluation::getValue(Position &dummyPosition, PositionContext *positionC
|
|||
#endif /* EVALUATE_MOBILITY */
|
||||
|
||||
switch (positionContext->action) {
|
||||
// 选子和落子使用相同的评价方法
|
||||
// 选子和落子使用相同的评价方法
|
||||
case ACTION_CHOOSE:
|
||||
case ACTION_PLACE:
|
||||
break;
|
||||
|
||||
// 如果形成去子状态,每有一个可去的子,算128分
|
||||
// 如果形成去子状态,每有一个可去的子,算128分
|
||||
case ACTION_CAPTURE:
|
||||
nPiecesNeedRemove = (positionContext->turn == PLAYER_1) ?
|
||||
positionContext->nPiecesNeedRemove : -(positionContext->nPiecesNeedRemove);
|
||||
|
@ -107,17 +107,13 @@ value_t Evaluation::getValue(Position &dummyPosition, PositionContext *positionC
|
|||
|
||||
break;
|
||||
|
||||
// 终局评价最简单
|
||||
// 终局评价最简单
|
||||
case PHASE_GAMEOVER:
|
||||
// 布局阶段闷棋判断
|
||||
if (positionContext->nPiecesOnBoard[1] + positionContext->nPiecesOnBoard[2] >=
|
||||
Board::N_SEATS * Board::N_RINGS) {
|
||||
if (dummyPosition.getRule()->isStartingPlayerLoseWhenBoardFull) {
|
||||
// winner = PLAYER_2;
|
||||
value -= VALUE_WIN;
|
||||
#ifdef DEBUG_AB_TREE
|
||||
node->result = -3;
|
||||
#endif
|
||||
} else {
|
||||
value = VALUE_DRAW;
|
||||
}
|
||||
|
@ -128,30 +124,15 @@ value_t Evaluation::getValue(Position &dummyPosition, PositionContext *positionC
|
|||
dummyPosition.context.board.isAllSurrounded(positionContext->turn, dummyPosition.currentRule, positionContext->nPiecesOnBoard, positionContext->turn) &&
|
||||
dummyPosition.getRule()->isLoseWhenNoWay) {
|
||||
// 规则要求被“闷”判负,则对手获胜
|
||||
if (positionContext->turn == PLAYER_1) {
|
||||
value -= VALUE_WIN;
|
||||
#ifdef DEBUG_AB_TREE
|
||||
node->result = -2;
|
||||
#endif
|
||||
} else {
|
||||
value += VALUE_WIN;
|
||||
#ifdef DEBUG_AB_TREE
|
||||
node->result = 2;
|
||||
#endif
|
||||
}
|
||||
value_t delta = positionContext->turn == PLAYER_1 ? -VALUE_WIN : VALUE_WIN;
|
||||
value += delta;
|
||||
}
|
||||
|
||||
// 剩余棋子个数判断
|
||||
if (positionContext->nPiecesOnBoard[1] < dummyPosition.getRule()->nPiecesAtLeast) {
|
||||
value -= VALUE_WIN;
|
||||
#ifdef DEBUG_AB_TREE
|
||||
node->result = -1;
|
||||
#endif
|
||||
} else if (positionContext->nPiecesOnBoard[2] < dummyPosition.getRule()->nPiecesAtLeast) {
|
||||
value += VALUE_WIN;
|
||||
#ifdef DEBUG_AB_TREE
|
||||
node->result = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <random>
|
||||
|
||||
#include "movegen.h"
|
||||
#include "player.h"
|
||||
#include "misc.h"
|
||||
|
||||
void MoveList::generateLegalMoves(MillGameAi_ab &ai_ab, Position &dummyPosition,
|
||||
|
@ -36,20 +37,14 @@ void MoveList::generateLegalMoves(MillGameAi_ab &ai_ab, Position &dummyPosition,
|
|||
switch (dummyPosition.getPhase()) {
|
||||
case PHASE_PLACING:
|
||||
if (dummyPosition.getAction() == ACTION_CAPTURE) {
|
||||
if (dummyPosition.whosTurn() == PLAYER_1)
|
||||
newCapacity = static_cast<size_t>(dummyPosition.getPiecesOnBoardCount(2));
|
||||
else
|
||||
newCapacity = static_cast<size_t>(dummyPosition.getPiecesOnBoardCount(1));
|
||||
newCapacity = static_cast<size_t>(dummyPosition.getPiecesOnBoardCount(dummyPosition.context.opponentId));
|
||||
} else {
|
||||
newCapacity = static_cast<size_t>(dummyPosition.getPiecesInHandCount(1) + dummyPosition.getPiecesInHandCount(2));
|
||||
}
|
||||
break;
|
||||
case PHASE_MOVING:
|
||||
if (dummyPosition.getAction() == ACTION_CAPTURE) {
|
||||
if (dummyPosition.whosTurn() == PLAYER_1)
|
||||
newCapacity = static_cast<size_t>(dummyPosition.getPiecesOnBoardCount(2));
|
||||
else
|
||||
newCapacity = static_cast<size_t>(dummyPosition.getPiecesOnBoardCount(1));
|
||||
newCapacity = static_cast<size_t>(dummyPosition.getPiecesOnBoardCount(dummyPosition.context.opponentId));
|
||||
} else {
|
||||
newCapacity = 6;
|
||||
}
|
||||
|
@ -70,7 +65,7 @@ void MoveList::generateLegalMoves(MillGameAi_ab &ai_ab, Position &dummyPosition,
|
|||
}
|
||||
|
||||
// 对手
|
||||
player_t opponent = Position::getOpponent(dummyPosition.context.turn);
|
||||
player_t opponent = Player::getOpponent(dummyPosition.context.turn);
|
||||
|
||||
// 列出所有合法的下一招
|
||||
switch (dummyPosition.context.action) {
|
||||
|
@ -110,10 +105,8 @@ void MoveList::generateLegalMoves(MillGameAi_ab &ai_ab, Position &dummyPosition,
|
|||
continue;
|
||||
}
|
||||
|
||||
if ((dummyPosition.context.turn == PLAYER_1 &&
|
||||
(dummyPosition.context.nPiecesOnBoard[1] > dummyPosition.currentRule.nPiecesAtLeast || !dummyPosition.currentRule.allowFlyWhenRemainThreePieces)) ||
|
||||
(dummyPosition.context.turn == PLAYER_2 &&
|
||||
(dummyPosition.context.nPiecesOnBoard[2] > dummyPosition.currentRule.nPiecesAtLeast || !dummyPosition.currentRule.allowFlyWhenRemainThreePieces))) {
|
||||
if (dummyPosition.context.nPiecesOnBoard[dummyPosition.context.turnId] > dummyPosition.currentRule.nPiecesAtLeast ||
|
||||
!dummyPosition.currentRule.allowFlyWhenRemainThreePieces) {
|
||||
// 对于棋盘上还有3个子以上,或不允许飞子的情况,要求必须在着法表中
|
||||
for (int direction = DIRECTION_CLOCKWISE; direction <= DIRECTION_OUTWARD; direction++) {
|
||||
// 对于原有位置,遍历四个方向的着法,如果棋盘上为空位就加到结点列表中
|
||||
|
|
|
@ -149,7 +149,6 @@ struct MillGameAi_ab::Node *MillGameAi_ab::addNode(
|
|||
newNode->nPiecesNeedRemove = INT_MAX;
|
||||
newNode->alpha = -VALUE_INFINITE;
|
||||
newNode->beta = VALUE_INFINITE;
|
||||
newNode->result = 0;
|
||||
newNode->visited = false;
|
||||
|
||||
int r, s;
|
||||
|
@ -233,11 +232,9 @@ void MillGameAi_ab::sortLegalMoves(Node *node)
|
|||
{
|
||||
// 这个函数对效率的影响很大,排序好的话,剪枝较早,节省时间,但不能在此函数耗费太多时间
|
||||
|
||||
if (dummyPosition.whosTurn() == PLAYER_1) {
|
||||
std::stable_sort(node->children.begin(), node->children.end(), nodeGreater);
|
||||
} else {
|
||||
std::stable_sort(node->children.begin(), node->children.end(), nodeLess);
|
||||
}
|
||||
auto cmp = dummyPosition.context.turn == PLAYER_1 ? nodeGreater : nodeLess;
|
||||
|
||||
std::stable_sort(node->children.begin(), node->children.end(), cmp);
|
||||
}
|
||||
|
||||
void MillGameAi_ab::deleteTree(Node *node)
|
||||
|
@ -490,11 +487,8 @@ value_t MillGameAi_ab::alphaBetaPruning(depth_t depth, value_t alpha, value_t be
|
|||
evaluatedNodeCount++;
|
||||
|
||||
// 为争取速胜,value 值 +- 深度 (有必要?)
|
||||
if (positionContext->turn == PLAYER_1) {
|
||||
node->value += depth;
|
||||
} else {
|
||||
node->value -= depth;
|
||||
}
|
||||
value_t delta = value_t(positionContext->turn == PLAYER_1 ? depth : -depth);
|
||||
node->value += delta;
|
||||
|
||||
#ifdef DEBUG_AB_TREE
|
||||
if (requiredQuit) {
|
||||
|
@ -505,8 +499,8 @@ value_t MillGameAi_ab::alphaBetaPruning(depth_t depth, value_t alpha, value_t be
|
|||
#ifdef BOOK_LEARNING
|
||||
// 检索开局库
|
||||
if (positionContext->phase == GAME_PLACING && findBookHash(hash, hashValue)) {
|
||||
if (positionContext->turn == PLAYER_2) {
|
||||
// 是否需对后手扣分 // TODO: 先后手都处理
|
||||
if (positionContext->turn == ???) {
|
||||
// TODO:
|
||||
node->value += 1;
|
||||
}
|
||||
}
|
||||
|
@ -525,7 +519,7 @@ value_t MillGameAi_ab::alphaBetaPruning(depth_t depth, value_t alpha, value_t be
|
|||
|
||||
// 根据演算模型执行 MiniMax 检索,对先手,搜索 Max, 对后手,搜索 Min
|
||||
|
||||
minMax = dummyPosition.whosTurn() == PLAYER_1 ? -VALUE_INFINITE : VALUE_INFINITE;
|
||||
minMax = dummyPosition.context.turn == PLAYER_1 ? -VALUE_INFINITE : VALUE_INFINITE;
|
||||
|
||||
for (auto child : node->children) {
|
||||
// 上下文入栈保存,以便后续撤销着法
|
||||
|
@ -556,7 +550,7 @@ value_t MillGameAi_ab::alphaBetaPruning(depth_t depth, value_t alpha, value_t be
|
|||
dummyPosition.context = contextStack.top();
|
||||
contextStack.pop();
|
||||
|
||||
if (dummyPosition.whosTurn() == PLAYER_1) {
|
||||
if (dummyPosition.context.turn == PLAYER_1) {
|
||||
// 为走棋一方的层, 局面对走棋的一方来说是以 α 为评价
|
||||
|
||||
// 取最大值
|
||||
|
@ -689,12 +683,11 @@ const char* MillGameAi_ab::bestMove()
|
|||
if (position_.getGiveUpIfMostLose() == true) {
|
||||
bool isMostLose = true; // 是否必败
|
||||
|
||||
player_t whosTurn = position_.whosTurn();
|
||||
player_t whosTurn = position_.context.turn;
|
||||
|
||||
for (auto child : rootNode->children) {
|
||||
// TODO: 使用常量代替
|
||||
if ((whosTurn == PLAYER_1 && child->value > -10000) ||
|
||||
(whosTurn == PLAYER_2 && child->value < 10000)) {
|
||||
if ((whosTurn == PLAYER_1 && child->value > -VALUE_WIN) ||
|
||||
(whosTurn == PLAYER_2 && child->value < VALUE_WIN)) {
|
||||
isMostLose = false;
|
||||
break;
|
||||
}
|
||||
|
@ -702,12 +695,7 @@ const char* MillGameAi_ab::bestMove()
|
|||
|
||||
// 自动认输
|
||||
if (isMostLose) {
|
||||
if (whosTurn == PLAYER_1) {
|
||||
sprintf(cmdline, "Player1 give up!");
|
||||
} else if (whosTurn == PLAYER_2) {
|
||||
sprintf(cmdline, "Player2 give up!");
|
||||
}
|
||||
|
||||
sprintf(cmdline, "Player%d give up!", position_.context.turnChar);
|
||||
return cmdline;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,7 +80,6 @@ public:
|
|||
int nPiecesOnBoardDiff; // 场上棋子个数和对手的差值
|
||||
int nPiecesInHandDiff; // 手中的棋子个数和对手的差值
|
||||
int nPiecesNeedRemove; // 手中有多少可去的子,如对手有可去的子则为负数
|
||||
int result; // 终局结果,-1为负,0为未到终局,1为胜,走棋阶段被闷棋则为 -2/2,布局阶段闷棋为 -3
|
||||
struct Node* root; // 根节点
|
||||
#ifdef TRANSPOSITION_TABLE_ENABLE
|
||||
bool isHash; // 是否从 Hash 读取
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <QTimer>
|
||||
#include "thread.h"
|
||||
#include "tt.h"
|
||||
#include "player.h"
|
||||
|
||||
AiThread::AiThread(int id, QObject *parent) :
|
||||
QThread(parent),
|
||||
|
@ -107,7 +108,7 @@ void AiThread::run()
|
|||
while (!isInterruptionRequested()) {
|
||||
mutex.lock();
|
||||
|
||||
i = Position::playerToId(position_->whosTurn());
|
||||
i = Player::toId(position_->context.turn);
|
||||
|
||||
if (i != id || waiting_) {
|
||||
pauseCondition.wait(&mutex);
|
||||
|
|
|
@ -36,6 +36,7 @@ class AiThread : public QThread
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AiThread(QObject *parent = nullptr);
|
||||
explicit AiThread(int id, QObject *parent = nullptr);
|
||||
~AiThread() override;
|
||||
|
||||
|
@ -90,10 +91,12 @@ public slots:
|
|||
// 发射着法信号
|
||||
void emitCommand();
|
||||
|
||||
private:
|
||||
public:
|
||||
// 玩家ID
|
||||
int id;
|
||||
|
||||
private:
|
||||
|
||||
// 发射的指令
|
||||
const char* strCommand {};
|
||||
|
||||
|
|
|
@ -302,10 +302,10 @@ int Board::addMills(const Rule ¤tRule, int location)
|
|||
return n;
|
||||
}
|
||||
|
||||
bool Board::isAllInMills(char ch)
|
||||
bool Board::isAllInMills(enum player_t player)
|
||||
{
|
||||
for (int i = LOCATION_BEGIN; i < LOCATION_END; i++) {
|
||||
if (locations[i] & ch) {
|
||||
if (locations[i] & (uint8_t)player) {
|
||||
if (!inHowManyMills(i)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -315,29 +315,14 @@ bool Board::isAllInMills(char ch)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Board::isAllInMills(enum player_t player)
|
||||
{
|
||||
char ch = 0x00;
|
||||
|
||||
if (player == PLAYER_1)
|
||||
ch = 0x10;
|
||||
else if (player == PLAYER_2)
|
||||
ch = 0x20;
|
||||
else
|
||||
return true;
|
||||
|
||||
return isAllInMills(ch);
|
||||
}
|
||||
|
||||
// 判断玩家的棋子周围有几个空位
|
||||
int Board::getSurroundedEmptyLocationCount(enum player_t turn, const Rule ¤tRule, int nPiecesOnBoard[], int location, bool includeFobidden)
|
||||
int Board::getSurroundedEmptyLocationCount(int turnId, const Rule ¤tRule, int nPiecesOnBoard[],
|
||||
int location, bool includeFobidden)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
if ((turn == PLAYER_1 &&
|
||||
(nPiecesOnBoard[1] > currentRule.nPiecesAtLeast || !currentRule.allowFlyWhenRemainThreePieces)) ||
|
||||
(turn == PLAYER_2 &&
|
||||
(nPiecesOnBoard[2] > currentRule.nPiecesAtLeast || !currentRule.allowFlyWhenRemainThreePieces))) {
|
||||
if (nPiecesOnBoard[turnId] > currentRule.nPiecesAtLeast ||
|
||||
!currentRule.allowFlyWhenRemainThreePieces) {
|
||||
int moveLocation;
|
||||
for (direction_t d = DIRECTION_BEGIN; d < DIRECTIONS_COUNT; d = (direction_t)(d + 1)) {
|
||||
moveLocation = MoveList::moveTable[location][d];
|
||||
|
@ -354,13 +339,11 @@ int Board::getSurroundedEmptyLocationCount(enum player_t turn, const Rule &curre
|
|||
}
|
||||
|
||||
// 判断玩家的棋子是否被围
|
||||
bool Board::isSurrounded(enum player_t turn, const Rule ¤tRule, int nPiecesOnBoard[], int location)
|
||||
bool Board::isSurrounded(int turnId, const Rule ¤tRule, int nPiecesOnBoard[], int location)
|
||||
{
|
||||
// 判断location处的棋子是否被“闷”
|
||||
if ((turn == PLAYER_1 &&
|
||||
(nPiecesOnBoard[1] > currentRule.nPiecesAtLeast || !currentRule.allowFlyWhenRemainThreePieces)) ||
|
||||
(turn == PLAYER_2 &&
|
||||
(nPiecesOnBoard[2] > currentRule.nPiecesAtLeast || !currentRule.allowFlyWhenRemainThreePieces))) {
|
||||
if (nPiecesOnBoard[turnId] > currentRule.nPiecesAtLeast ||
|
||||
!currentRule.allowFlyWhenRemainThreePieces) {
|
||||
int i, moveLocation;
|
||||
for (i = 0; i < 4; i++) {
|
||||
moveLocation = MoveList::moveTable[location][i];
|
||||
|
@ -375,17 +358,15 @@ bool Board::isSurrounded(enum player_t turn, const Rule ¤tRule, int nPiece
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Board::isAllSurrounded(enum player_t turn, const Rule ¤tRule, int nPiecesOnBoard[], char ch)
|
||||
bool Board::isAllSurrounded(int turnId, const Rule ¤tRule, int nPiecesOnBoard[], char ch)
|
||||
{
|
||||
// 如果摆满
|
||||
if (nPiecesOnBoard[1] + nPiecesOnBoard[2] >= N_SEATS * N_RINGS)
|
||||
return true;
|
||||
|
||||
// 判断是否可以飞子
|
||||
if ((turn == PLAYER_1 &&
|
||||
(nPiecesOnBoard[1] <= currentRule.nPiecesAtLeast && currentRule.allowFlyWhenRemainThreePieces)) ||
|
||||
(turn == PLAYER_2 &&
|
||||
(nPiecesOnBoard[2] <= currentRule.nPiecesAtLeast && currentRule.allowFlyWhenRemainThreePieces))) {
|
||||
if (nPiecesOnBoard[turnId] <= currentRule.nPiecesAtLeast &&
|
||||
currentRule.allowFlyWhenRemainThreePieces) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -407,32 +388,27 @@ bool Board::isAllSurrounded(enum player_t turn, const Rule ¤tRule, int nPi
|
|||
}
|
||||
|
||||
// 判断玩家的棋子是否全部被围
|
||||
bool Board::isAllSurrounded(enum player_t turn, const Rule ¤tRule, int nPiecesOnBoard[], enum player_t ply)
|
||||
bool Board::isAllSurrounded(int turnId, const Rule ¤tRule, int nPiecesOnBoard[], enum player_t ply)
|
||||
{
|
||||
char t = '\x30';
|
||||
char t = 0x30 & ply;
|
||||
|
||||
if (ply == PLAYER_1)
|
||||
t &= '\x10';
|
||||
else if (ply == PLAYER_2)
|
||||
t &= '\x20';
|
||||
|
||||
return isAllSurrounded(turn, currentRule, nPiecesOnBoard, t);
|
||||
return isAllSurrounded(turnId, currentRule, nPiecesOnBoard, t);
|
||||
}
|
||||
|
||||
#if 0
|
||||
enum player_t Board::getWhosPiece(int r, int s)
|
||||
{
|
||||
int location = polarToLocation(r, s);
|
||||
|
||||
if (locations[location] & '\x10')
|
||||
if (locations[location] & PLAYER_1)
|
||||
return PLAYER_1;
|
||||
|
||||
if (locations[location] & '\x20')
|
||||
if (locations[location] & PLAYER_2)
|
||||
return PLAYER_2;
|
||||
|
||||
return PLAYER_NOBODY;
|
||||
}
|
||||
|
||||
// Unused
|
||||
bool Board::getPieceRS(const player_t &player, const int &number, int &r, int &s, struct Rule ¤tRule)
|
||||
{
|
||||
int piece;
|
||||
|
@ -480,6 +456,7 @@ bool Board::getCurrentPiece(player_t &player, int &number, int location)
|
|||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool Board::isStarLocation(int location)
|
||||
{
|
||||
|
|
|
@ -78,27 +78,28 @@ public:
|
|||
int inHowManyMills(int location);
|
||||
|
||||
// 判断玩家的所有棋子是否都处于“三连”状态
|
||||
bool isAllInMills(char ch);
|
||||
bool isAllInMills(enum player_t);
|
||||
|
||||
// 判断玩家的棋子周围有几个空位
|
||||
int getSurroundedEmptyLocationCount(enum player_t turn, const Rule ¤tRule, int nPiecesOnBoard[], int location, bool includeFobidden);
|
||||
int getSurroundedEmptyLocationCount(int turnId, const Rule ¤tRule, int nPiecesOnBoard[], int location, bool includeFobidden);
|
||||
|
||||
// 判断玩家的棋子是否被围
|
||||
bool isSurrounded(enum player_t turn, const Rule ¤tRule, int nPiecesOnBoard[], int location);
|
||||
bool isSurrounded(int turnId, const Rule ¤tRule, int nPiecesOnBoard[], int location);
|
||||
|
||||
// 判断玩家的棋子是否全部被围
|
||||
bool isAllSurrounded(enum player_t turn, const Rule ¤tRule, int nPiecesOnBoard[], char ch);
|
||||
bool isAllSurrounded(int turnId, const Rule ¤tRule, int nPiecesOnBoard[], char ch);
|
||||
|
||||
bool isAllSurrounded(enum player_t turn, const Rule ¤tRule, int nPiecesOnBoard[], enum player_t ply);
|
||||
bool isAllSurrounded(int turnId, const Rule ¤tRule, int nPiecesOnBoard[], enum player_t ply);
|
||||
|
||||
// 三连加入列表
|
||||
int addMills(const Rule ¤tRule, int location);
|
||||
|
||||
#if 0
|
||||
// 获取位置点棋子的归属人
|
||||
enum player_t getWhosPiece(int r, int s);
|
||||
|
||||
bool getPieceRS(const player_t &player, const int &number, int &r, int &s, struct Rule ¤tRule);
|
||||
#endif
|
||||
|
||||
// 获取当前棋子
|
||||
bool getCurrentPiece(player_t &player, int &number, int currentPos);
|
||||
|
|
|
@ -20,35 +20,66 @@
|
|||
*****************************************************************************/
|
||||
|
||||
#ifndef PLAYER_H
|
||||
#define PLAYER_H
|
||||
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
#define PLAYER_H
|
||||
|
||||
class Player
|
||||
{
|
||||
public:
|
||||
explicit Player();
|
||||
virtual ~Player();
|
||||
|
||||
const player_t getPlayer() const
|
||||
{
|
||||
return who;
|
||||
}
|
||||
|
||||
int getId() const
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
inline static int toId(player_t who)
|
||||
{
|
||||
return int((int)who >> PLAYER_SHIFT);
|
||||
}
|
||||
|
||||
private:
|
||||
player_t who;
|
||||
int id;
|
||||
};
|
||||
|
||||
#endif // PLAYER_H
|
||||
#include <string>
|
||||
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
|
||||
class Player
|
||||
{
|
||||
public:
|
||||
explicit Player();
|
||||
virtual ~Player();
|
||||
|
||||
player_t getPlayer() const
|
||||
{
|
||||
return who;
|
||||
}
|
||||
|
||||
int getId() const
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
inline static int toId(player_t who)
|
||||
{
|
||||
return int(static_cast<int>(who) >> PLAYER_SHIFT);
|
||||
}
|
||||
|
||||
inline static player_t idToPlayer(int id)
|
||||
{
|
||||
return player_t(id << PLAYER_SHIFT);
|
||||
}
|
||||
|
||||
inline static char idToCh(int id)
|
||||
{
|
||||
return static_cast<char>('0' + id);
|
||||
}
|
||||
|
||||
inline static std::string chToStr(char ch)
|
||||
{
|
||||
if (ch == '1') {
|
||||
return "1";
|
||||
} else {
|
||||
return "2";
|
||||
}
|
||||
}
|
||||
|
||||
inline static player_t getOpponent(player_t player)
|
||||
{
|
||||
return player == PLAYER_1 ? PLAYER_2 : PLAYER_1;
|
||||
}
|
||||
|
||||
inline static int getOpponentById(int id)
|
||||
{
|
||||
return id == 1 ? 2 : 1;
|
||||
}
|
||||
|
||||
private:
|
||||
player_t who;
|
||||
int id;
|
||||
};
|
||||
|
||||
#endif // PLAYER_H
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "position.h"
|
||||
#include "search.h"
|
||||
#include "movegen.h"
|
||||
#include "player.h"
|
||||
|
||||
Position::Position()
|
||||
{
|
||||
|
@ -41,7 +42,7 @@ Position::Position()
|
|||
setContext(&RULES[1]);
|
||||
|
||||
// 比分归零
|
||||
score_1 = score_2 = score_draw = 0;
|
||||
score[1] = score[2] = score_draw = 0;
|
||||
}
|
||||
|
||||
Position::~Position() = default;
|
||||
|
@ -67,8 +68,8 @@ Position &Position::operator= (const Position &position)
|
|||
winner = position.winner;
|
||||
startTime = position.startTime;
|
||||
currentTime = position.currentTime;
|
||||
elapsedSeconds_1 = position.elapsedSeconds_1;
|
||||
elapsedSeconds_2 = position.elapsedSeconds_2;
|
||||
elapsedSeconds[1] = position.elapsedSeconds[1];
|
||||
elapsedSeconds[2] = position.elapsedSeconds[2];
|
||||
move_ = position.move_;
|
||||
memcpy(cmdline, position.cmdline, sizeof(cmdline));
|
||||
cmdlist = position.cmdlist;
|
||||
|
@ -77,31 +78,6 @@ Position &Position::operator= (const Position &position)
|
|||
return *this;
|
||||
}
|
||||
|
||||
int Position::playerToId(enum player_t player)
|
||||
{
|
||||
if (player == PLAYER_1)
|
||||
return 1;
|
||||
else if (player == PLAYER_2)
|
||||
return 2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
player_t Position::getOpponent(enum player_t player)
|
||||
{
|
||||
switch (player)
|
||||
{
|
||||
case PLAYER_1:
|
||||
return PLAYER_2;
|
||||
case PLAYER_2:
|
||||
return PLAYER_1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return PLAYER_NOBODY;
|
||||
}
|
||||
|
||||
// 设置配置
|
||||
bool Position::configure(bool giveUpIfMostLose, bool randomMove)
|
||||
{
|
||||
|
@ -141,7 +117,7 @@ bool Position::setContext(const struct Rule *rule, step_t maxStepsLedToDraw, int
|
|||
context.phase = phase;
|
||||
|
||||
// 轮流状态标识
|
||||
context.turn = turn;
|
||||
setTurn(turn);
|
||||
|
||||
// 动作状态标识
|
||||
context.action = action;
|
||||
|
@ -221,7 +197,7 @@ bool Position::setContext(const struct Rule *rule, step_t maxStepsLedToDraw, int
|
|||
currentLocation = 0;
|
||||
|
||||
// 用时置零
|
||||
elapsedSeconds_1 = elapsedSeconds_2 = 0;
|
||||
elapsedSeconds[1] = elapsedSeconds[2] = 0;
|
||||
|
||||
// 提示
|
||||
setTips();
|
||||
|
@ -244,25 +220,10 @@ bool Position::setContext(const struct Rule *rule, step_t maxStepsLedToDraw, int
|
|||
return false;
|
||||
}
|
||||
|
||||
void Position::getContext(struct Rule &rule, step_t &step,
|
||||
phase_t &phase, player_t &turn, action_t &action,
|
||||
int *&locations, int &nPiecesInHand_1, int &nPiecesInHand_2, int &nPiecesNeedRemove)
|
||||
{
|
||||
rule = this->currentRule;
|
||||
step = this->currentStep;
|
||||
phase = context.phase;
|
||||
turn = context.turn;
|
||||
action = context.action;
|
||||
boardLocations = locations;
|
||||
nPiecesInHand_1 = context.nPiecesInHand[1];
|
||||
nPiecesInHand_2 = context.nPiecesInHand[2];
|
||||
nPiecesNeedRemove = context.nPiecesNeedRemove;
|
||||
}
|
||||
|
||||
bool Position::reset()
|
||||
{
|
||||
if (context.phase == PHASE_NOTSTARTED &&
|
||||
elapsedSeconds_1 == elapsedSeconds_2 == 0) {
|
||||
elapsedSeconds[1] == elapsedSeconds[2] == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -273,8 +234,8 @@ bool Position::reset()
|
|||
// 局面阶段标识
|
||||
context.phase = PHASE_NOTSTARTED;
|
||||
|
||||
// 轮流状态标识
|
||||
context.turn = PLAYER_1;
|
||||
// 设置轮流状态
|
||||
setTurn(PLAYER_1);
|
||||
|
||||
// 动作状态标识
|
||||
context.action = ACTION_PLACE;
|
||||
|
@ -303,7 +264,7 @@ bool Position::reset()
|
|||
currentLocation = 0;
|
||||
|
||||
// 用时置零
|
||||
elapsedSeconds_1 = elapsedSeconds_2 = 0;
|
||||
elapsedSeconds[1] = elapsedSeconds[2] = 0;
|
||||
|
||||
// 哈希归零
|
||||
context.hash = 0;
|
||||
|
@ -386,18 +347,10 @@ bool Position::place(int location, int time_p, int8_t rs)
|
|||
int n = 0;
|
||||
|
||||
if (context.phase == PHASE_PLACING) {
|
||||
// 先手下
|
||||
if (context.turn == PLAYER_1) {
|
||||
piece = '\x11' + currentRule.nTotalPiecesEachSide - context.nPiecesInHand[1];
|
||||
context.nPiecesInHand[1]--;
|
||||
context.nPiecesOnBoard[1]++;
|
||||
}
|
||||
// 后手下
|
||||
else {
|
||||
piece = '\x21' + currentRule.nTotalPiecesEachSide - context.nPiecesInHand[2];
|
||||
context.nPiecesInHand[2]--;
|
||||
context.nPiecesOnBoard[2]++;
|
||||
}
|
||||
int playerId = Player::toId(context.turn);
|
||||
piece = (0x01 | context.turn) + currentRule.nTotalPiecesEachSide - context.nPiecesInHand[playerId];
|
||||
context.nPiecesInHand[playerId]--;
|
||||
context.nPiecesOnBoard[playerId]++;
|
||||
|
||||
boardLocations[location] = piece;
|
||||
|
||||
|
@ -432,9 +385,9 @@ bool Position::place(int location, int time_p, int8_t rs)
|
|||
|
||||
// 设置轮到谁走
|
||||
if (currentRule.isDefenderMoveFirst) {
|
||||
context.turn = PLAYER_2;
|
||||
setTurn(PLAYER_2);
|
||||
} else {
|
||||
context.turn = PLAYER_1;
|
||||
setTurn(PLAYER_1);
|
||||
}
|
||||
|
||||
// 再决胜负
|
||||
|
@ -468,11 +421,8 @@ bool Position::place(int location, int time_p, int8_t rs)
|
|||
// 对于中局落子 (ontext.phase == GAME_MOVING)
|
||||
|
||||
// 如果落子不合法
|
||||
if ((context.turn == PLAYER_1 &&
|
||||
(context.nPiecesOnBoard[1] > currentRule.nPiecesAtLeast || !currentRule.allowFlyWhenRemainThreePieces)) ||
|
||||
(context.turn == PLAYER_2 &&
|
||||
(context.nPiecesOnBoard[2] > currentRule.nPiecesAtLeast || !currentRule.allowFlyWhenRemainThreePieces))) {
|
||||
|
||||
if (context.nPiecesOnBoard[context.turnId] > currentRule.nPiecesAtLeast ||
|
||||
!currentRule.allowFlyWhenRemainThreePieces) {
|
||||
int i;
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (location == MoveList::moveTable[currentLocation][i])
|
||||
|
@ -576,8 +526,7 @@ bool Position::capture(int location, int time_p, int8_t cp)
|
|||
// 时间的临时变量
|
||||
int player_ms = -1;
|
||||
|
||||
// 对手
|
||||
char opponent = context.turn == PLAYER_1 ? 0x20 : 0x10;
|
||||
player_t opponent = Player::getOpponent(context.turn);
|
||||
|
||||
// 判断去子是不是对手棋
|
||||
if (!(opponent & boardLocations[location]))
|
||||
|
@ -600,10 +549,7 @@ bool Position::capture(int location, int time_p, int8_t cp)
|
|||
boardLocations[location] = '\x00';
|
||||
}
|
||||
|
||||
if (context.turn == PLAYER_1)
|
||||
context.nPiecesOnBoard[2]--;
|
||||
else if (context.turn == PLAYER_2)
|
||||
context.nPiecesOnBoard[1]--;
|
||||
context.nPiecesOnBoard[context.opponentId]--;
|
||||
|
||||
move_ = static_cast<move_t>(-location);
|
||||
|
||||
|
@ -650,9 +596,9 @@ bool Position::capture(int location, int time_p, int8_t cp)
|
|||
|
||||
// 设置轮到谁走
|
||||
if (currentRule.isDefenderMoveFirst) {
|
||||
context.turn = PLAYER_2;
|
||||
setTurn(PLAYER_2);
|
||||
} else {
|
||||
context.turn = PLAYER_1;
|
||||
setTurn(PLAYER_1);
|
||||
}
|
||||
|
||||
// 再决胜负
|
||||
|
@ -706,12 +652,10 @@ bool Position::choose(int location)
|
|||
if (context.action != ACTION_CHOOSE && context.action != ACTION_PLACE)
|
||||
return false;
|
||||
|
||||
char t = context.turn == PLAYER_1 ? 0x10 : 0x20;
|
||||
|
||||
// 判断选子是否可选
|
||||
if (boardLocations[location] & t) {
|
||||
if (boardLocations[location] & context.turn) {
|
||||
// 判断location处的棋子是否被“闷”
|
||||
if (context.board.isSurrounded(context.turn, currentRule, context.nPiecesOnBoard, location)) {
|
||||
if (context.board.isSurrounded(context.turnId, currentRule, context.nPiecesOnBoard, location)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -742,17 +686,14 @@ bool Position::giveup(player_t loser)
|
|||
|
||||
context.phase = PHASE_GAMEOVER;
|
||||
|
||||
if (loser == PLAYER_1) {
|
||||
winner = PLAYER_2;
|
||||
tips = "玩家1投子认负。";
|
||||
sprintf(cmdline, "Player1 give up!");
|
||||
score_2++;
|
||||
} else if (loser == PLAYER_2) {
|
||||
winner = PLAYER_1;
|
||||
tips = "玩家2投子认负。";
|
||||
sprintf(cmdline, "Player2 give up!");
|
||||
score_1++;
|
||||
}
|
||||
int loserId = Player::toId(loser);
|
||||
char loserCh = Player::idToCh(loserId);
|
||||
string loserStr = Player::chToStr(loserCh);
|
||||
|
||||
winner = Player::getOpponent(loser);
|
||||
tips = "玩家" + loserStr + "投子认负";
|
||||
sprintf(cmdline, "Player%d give up!", loserId);
|
||||
score[Player::toId(winner)]++;
|
||||
|
||||
cmdlist.emplace_back(string(cmdline));
|
||||
|
||||
|
@ -818,12 +759,7 @@ bool Position::command(const char *cmd)
|
|||
args = sscanf(cmd, "Player%1u give up!", &t);
|
||||
|
||||
if (args == 1) {
|
||||
if (t == 1) {
|
||||
return giveup(PLAYER_1);
|
||||
}
|
||||
if (t == 2) {
|
||||
return giveup(PLAYER_2);
|
||||
}
|
||||
return giveup(Player::idToPlayer(t));
|
||||
}
|
||||
|
||||
#ifdef THREEFOLD_REPETITION
|
||||
|
@ -865,8 +801,8 @@ bool Position::command(int move)
|
|||
inline int Position::update(int time_p /*= -1*/)
|
||||
{
|
||||
int ret = -1;
|
||||
time_t *player_ms = (context.turn == PLAYER_1 ? &elapsedSeconds_1 : &elapsedSeconds_2);
|
||||
time_t playerNext_ms = (context.turn == PLAYER_1 ? elapsedSeconds_2 : elapsedSeconds_1);
|
||||
time_t *player_ms = &elapsedSeconds[context.turnId];
|
||||
time_t playerNext_ms = elapsedSeconds[context.opponentId];
|
||||
|
||||
// 根据局面调整计时器
|
||||
|
||||
|
@ -879,7 +815,7 @@ inline int Position::update(int time_p /*= -1*/)
|
|||
// 更新时间
|
||||
if (time_p >= *player_ms) {
|
||||
*player_ms = ret = time_p;
|
||||
startTime = currentTime - (elapsedSeconds_1 + elapsedSeconds_2);
|
||||
startTime = currentTime - (elapsedSeconds[1] + elapsedSeconds[2]);
|
||||
} else {
|
||||
*player_ms = ret = currentTime - startTime - playerNext_ms;
|
||||
}
|
||||
|
@ -914,22 +850,18 @@ bool Position::win(bool forceDraw)
|
|||
context.phase = PHASE_GAMEOVER;
|
||||
|
||||
// 这里不能update更新时间,否则会形成循环嵌套
|
||||
// 如果玩家1超时
|
||||
if (elapsedSeconds_1 > currentRule.maxTimeLedToLose * 60) {
|
||||
elapsedSeconds_1 = currentRule.maxTimeLedToLose * 60;
|
||||
winner = PLAYER_2;
|
||||
tips = "玩家1超时判负。";
|
||||
sprintf(cmdline, "Time over. Player2 win!");
|
||||
}
|
||||
// 如果玩家2超时
|
||||
else if (elapsedSeconds_2 > currentRule.maxTimeLedToLose * 60) {
|
||||
elapsedSeconds_2 = currentRule.maxTimeLedToLose * 60;
|
||||
winner = PLAYER_1;
|
||||
tips = "玩家2超时判负。";
|
||||
sprintf(cmdline, "Time over. Player1 win!");
|
||||
for (int i = 1; i <= 2; i++)
|
||||
{
|
||||
if (elapsedSeconds[i] > currentRule.maxTimeLedToLose * 60) {
|
||||
elapsedSeconds[i] = currentRule.maxTimeLedToLose * 60;
|
||||
winner = Player::idToPlayer(Player::getOpponentById(i));
|
||||
tips = "玩家" + Player::chToStr(Player::idToCh(i)) + "超时判负。";
|
||||
sprintf(cmdline, "Time over. Player%d win!", Player::getOpponentById(i));
|
||||
}
|
||||
}
|
||||
|
||||
cmdlist.emplace_back(string(cmdline));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -943,25 +875,21 @@ bool Position::win(bool forceDraw)
|
|||
return true;
|
||||
}
|
||||
|
||||
// 如果玩家1子数小于赛点,则玩家2获胜
|
||||
if (context.nPiecesOnBoard[1] + context.nPiecesInHand[1] < currentRule.nPiecesAtLeast) {
|
||||
winner = PLAYER_2;
|
||||
context.phase = PHASE_GAMEOVER;
|
||||
sprintf(cmdline, "Player2 win!");
|
||||
cmdlist.emplace_back(string(cmdline));
|
||||
return true;
|
||||
}
|
||||
|
||||
// 如果玩家2子数小于赛点,则玩家1获胜
|
||||
if (context.nPiecesOnBoard[2] + context.nPiecesInHand[2] < currentRule.nPiecesAtLeast) {
|
||||
winner = PLAYER_1;
|
||||
context.phase = PHASE_GAMEOVER;
|
||||
sprintf(cmdline, "Player1 win!");
|
||||
cmdlist.emplace_back(string(cmdline));
|
||||
// 如果玩家子数小于赛点,则对方获胜
|
||||
for (int i = 1; i <= 2; i++)
|
||||
{
|
||||
if (context.nPiecesOnBoard[i] + context.nPiecesInHand[i] < currentRule.nPiecesAtLeast) {
|
||||
int o = Player::getOpponentById(i);
|
||||
winner = Player::idToPlayer(o);
|
||||
context.phase = PHASE_GAMEOVER;
|
||||
sprintf(cmdline, "Player%d win!", o);
|
||||
cmdlist.emplace_back(string(cmdline));
|
||||
#ifdef BOOK_LEARNING
|
||||
MillGameAi_ab::recordOpeningBookToHashMap(); // 暂时只对后手的失败记录到开局库
|
||||
MillGameAi_ab::recordOpeningBookToHashMap(); // TODO: 目前是对"双方"失败都记录到开局库
|
||||
#endif /* BOOK_LEARNING */
|
||||
return true;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果摆满了,根据规则判断胜负
|
||||
|
@ -977,6 +905,7 @@ bool Position::win(bool forceDraw)
|
|||
}
|
||||
|
||||
cmdlist.emplace_back(string(cmdline));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -986,26 +915,21 @@ bool Position::win(bool forceDraw)
|
|||
context.phase = PHASE_GAMEOVER;
|
||||
|
||||
if (currentRule.isLoseWhenNoWay) {
|
||||
if (context.turn == PLAYER_1) {
|
||||
tips = "玩家1无子可走被闷。";
|
||||
winner = PLAYER_2;
|
||||
sprintf(cmdline, "Player1 no way to go. Player2 win!");
|
||||
cmdlist.emplace_back(string(cmdline));
|
||||
} else {
|
||||
tips = "玩家2无子可走被闷。";
|
||||
winner = PLAYER_1;
|
||||
sprintf(cmdline, "Player2 no way to go. Player1 win!");
|
||||
cmdlist.emplace_back(string(cmdline));
|
||||
tips = "玩家" + Player::chToStr(context.turnChar) + "无子可走被闷";
|
||||
winner = Player::getOpponent(context.turn);
|
||||
int winnerId = Player::toId(winner);
|
||||
sprintf(cmdline, "Player%d no way to go. Player%d win!", context.turnId, winnerId);
|
||||
cmdlist.emplace_back(string(cmdline));
|
||||
#ifdef BOOK_LEARNING
|
||||
MillGameAi_ab::recordOpeningBookToHashMap(); // 暂时只对后手的失败记录到开局库
|
||||
MillGameAi_ab::recordOpeningBookToHashMap(); // TODO: 目前是对所有的失败记录到开局库
|
||||
#endif /* BOOK_LEARNING */
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 否则让棋,由对手走
|
||||
changeTurn();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1064,71 +988,73 @@ void Position::cleanForbiddenLocations()
|
|||
}
|
||||
}
|
||||
|
||||
enum player_t Position::changeTurn()
|
||||
void Position::setTurn(player_t player)
|
||||
{
|
||||
// 设置轮到谁走
|
||||
context.turn = (context.turn == PLAYER_1) ? PLAYER_2 : PLAYER_1;
|
||||
context.turn = player;
|
||||
|
||||
return context.turn;
|
||||
context.turnId = Player::toId(context.turn);
|
||||
context.turnChar = Player::idToCh(context.turnId);
|
||||
//context.turnStr = Player::chToStr(context.turnChar);
|
||||
|
||||
context.opponent = Player::getOpponent(player);
|
||||
|
||||
context.opponentId = Player::toId(context.opponent);
|
||||
context.opponentChar = Player::idToCh(context.opponentId);
|
||||
//context.opponentStr = Player::chToStr(context.opponentChar);
|
||||
}
|
||||
|
||||
void Position::changeTurn()
|
||||
{
|
||||
setTurn(Player::getOpponent(context.turn));
|
||||
}
|
||||
|
||||
void Position::setTips()
|
||||
{
|
||||
string winnerStr, t;
|
||||
int winnerId;
|
||||
string turnStr = Player::chToStr(context.turnChar);
|
||||
|
||||
switch (context.phase) {
|
||||
case PHASE_NOTSTARTED:
|
||||
tips = "轮到玩家1落子,剩余" + std::to_string(context.nPiecesInHand[1]) + "子" +
|
||||
" 比分 " + to_string(score_1) + ":" + to_string(score_2) + ", 和棋 " + to_string(score_draw);
|
||||
" 比分 " + to_string(score[1]) + ":" + to_string(score[2]) + ", 和棋 " + to_string(score_draw);
|
||||
break;
|
||||
|
||||
case PHASE_PLACING:
|
||||
if (context.action == ACTION_PLACE) {
|
||||
if (context.turn == PLAYER_1) {
|
||||
tips = "轮到玩家1落子,剩余" + std::to_string(context.nPiecesInHand[1]) + "子";
|
||||
} else if (context.turn == PLAYER_2) {
|
||||
tips = "轮到玩家2落子,剩余" + std::to_string(context.nPiecesInHand[2]) + "子";
|
||||
}
|
||||
tips = "轮到玩家" + turnStr + "落子,剩余" + std::to_string(context.nPiecesInHand[context.turnId]) + "子";
|
||||
} else if (context.action == ACTION_CAPTURE) {
|
||||
if (context.turn == PLAYER_1) {
|
||||
tips = "成三!轮到玩家1去子,需去" + std::to_string(context.nPiecesNeedRemove) + "子";
|
||||
} else if (context.turn == PLAYER_2) {
|
||||
tips = "成三!轮到玩家2去子,需去" + std::to_string(context.nPiecesNeedRemove) + "子";
|
||||
}
|
||||
tips = "成三!轮到玩家" + turnStr + "去子,需去" + std::to_string(context.nPiecesNeedRemove) + "子";
|
||||
}
|
||||
break;
|
||||
|
||||
case PHASE_MOVING:
|
||||
if (context.action == ACTION_PLACE || context.action == ACTION_CHOOSE) {
|
||||
if (context.turn == PLAYER_1) {
|
||||
tips = "轮到玩家1选子移动";
|
||||
} else if (context.turn == PLAYER_2) {
|
||||
tips = "轮到玩家2选子移动";
|
||||
}
|
||||
tips = "轮到玩家" + turnStr + "选子移动";
|
||||
} else if (context.action == ACTION_CAPTURE) {
|
||||
if (context.turn == PLAYER_1) {
|
||||
tips = "成三!轮到玩家1去子,需去" + std::to_string(context.nPiecesNeedRemove) + "子";
|
||||
} else if (context.turn == PLAYER_2) {
|
||||
tips = "成三!轮到玩家2去子,需去" + std::to_string(context.nPiecesNeedRemove) + "子";
|
||||
}
|
||||
tips = "成三!轮到玩家" + turnStr + "去子,需去" + std::to_string(context.nPiecesNeedRemove) + "子";
|
||||
}
|
||||
break;
|
||||
|
||||
case PHASE_GAMEOVER:
|
||||
case PHASE_GAMEOVER:
|
||||
if (winner == PLAYER_DRAW) {
|
||||
score_draw++;
|
||||
tips = "双方平局!比分 " + to_string(score_1) + ":" + to_string(score_2) + ", 和棋 " + to_string(score_draw);
|
||||
}
|
||||
else if (winner == PLAYER_1) {
|
||||
score_1++;
|
||||
if (tips.find("无子可走") != string::npos)
|
||||
tips += "玩家1获胜!比分 " + to_string(score_1) + ":" + to_string(score_2) + ", 和棋 " + to_string(score_draw);
|
||||
else
|
||||
tips = "玩家1获胜!比分 " + to_string(score_1) + ":" + to_string(score_2) + ", 和棋 " + to_string(score_draw);
|
||||
} else if (winner == PLAYER_2) {
|
||||
score_2++;
|
||||
if (tips.find("无子可走") != string::npos)
|
||||
tips += "玩家2获胜!比分 " + to_string(score_1) + ":" + to_string(score_2) + ", 和棋 " + to_string(score_draw);
|
||||
else
|
||||
tips = "玩家2获胜!比分 " + to_string(score_1) + ":" + to_string(score_2) + ", 和棋 " + to_string(score_draw);
|
||||
tips = "双方平局!比分 " + to_string(score[1]) + ":" + to_string(score[2]) + ", 和棋 " + to_string(score_draw);
|
||||
break;
|
||||
}
|
||||
|
||||
winnerId = Player::toId(winner);
|
||||
winnerStr = Player::chToStr(Player::idToCh(winnerId));
|
||||
|
||||
score[winnerId]++;
|
||||
|
||||
t = "玩家" + winnerStr + "获胜!比分 " + to_string(score[1]) + ":" + to_string(score[2]) + ", 和棋 " + to_string(score_draw);
|
||||
|
||||
if (tips.find("无子可走") != string::npos) {
|
||||
tips += t;
|
||||
} else {
|
||||
tips = t;
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -1142,8 +1068,8 @@ void Position::getElapsedTime(time_t &p1_ms, time_t &p2_ms)
|
|||
{
|
||||
update();
|
||||
|
||||
p1_ms = elapsedSeconds_1;
|
||||
p2_ms = elapsedSeconds_2;
|
||||
p1_ms = elapsedSeconds[1];
|
||||
p2_ms = elapsedSeconds[2];
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -51,6 +51,13 @@ public:
|
|||
|
||||
// 轮流状态标识
|
||||
enum player_t turn;
|
||||
int turnId;
|
||||
char turnChar;
|
||||
//string turnStr;
|
||||
enum player_t opponent;
|
||||
int opponentId;
|
||||
char opponentChar;
|
||||
//string opponentStr;
|
||||
|
||||
// 动作状态标识
|
||||
enum action_t action
|
||||
|
@ -77,14 +84,9 @@ class Position
|
|||
|
||||
public:
|
||||
// 赢盘数
|
||||
int score_1 {};
|
||||
int score_2 {};
|
||||
int score[3];
|
||||
int score_draw {};
|
||||
|
||||
static int playerToId(enum player_t player);
|
||||
|
||||
static player_t getOpponent(enum player_t player);
|
||||
|
||||
private:
|
||||
|
||||
// 创建哈希值
|
||||
|
@ -115,12 +117,6 @@ public:
|
|||
int nPiecesNeedRemove = 0 // 尚待去除的子数
|
||||
);
|
||||
|
||||
// 获取棋局状态和棋盘上下文
|
||||
void getContext(struct Rule &rule, step_t &step,
|
||||
phase_t &phase, player_t &turn, action_t &action,
|
||||
int *&board,
|
||||
int &nPiecesInHand_1, int &nPiecesInHand_2, int &nPiecesNeedRemove);
|
||||
|
||||
// 获取当前规则
|
||||
const struct Rule *getRule() const
|
||||
{
|
||||
|
@ -169,12 +165,6 @@ public:
|
|||
return context.phase;
|
||||
}
|
||||
|
||||
// 获取轮流状态标识
|
||||
enum player_t whosTurn() const
|
||||
{
|
||||
return context.turn;
|
||||
}
|
||||
|
||||
// 获取动作状态标识
|
||||
enum action_t getAction() const
|
||||
{
|
||||
|
@ -272,8 +262,11 @@ public:
|
|||
// 清除所有禁点
|
||||
void cleanForbiddenLocations();
|
||||
|
||||
// 设置轮流
|
||||
void setTurn(player_t player);
|
||||
|
||||
// 改变轮流
|
||||
enum player_t changeTurn();
|
||||
void changeTurn();
|
||||
|
||||
// 设置提示
|
||||
void setTips();
|
||||
|
@ -358,11 +351,8 @@ private:
|
|||
// 当前游戏时间
|
||||
time_t currentTime {};
|
||||
|
||||
// 玩家1用时(秒)
|
||||
time_t elapsedSeconds_1 {};
|
||||
|
||||
// 玩家2用时(秒)
|
||||
time_t elapsedSeconds_2 {};
|
||||
// 玩家用时(秒)
|
||||
time_t elapsedSeconds[3];
|
||||
|
||||
// 当前棋局的字符提示
|
||||
string tips;
|
||||
|
|
|
@ -37,15 +37,11 @@
|
|||
|
||||
GameController::GameController(GameScene & scene, QObject * parent) :
|
||||
QObject(parent),
|
||||
ai1(1),
|
||||
ai2(2),
|
||||
scene(scene),
|
||||
currentPiece(nullptr),
|
||||
currentRow(-1),
|
||||
isEditing(false),
|
||||
isInverted(false),
|
||||
isAiPlayer_1(false),
|
||||
isAiPlayer_2(false),
|
||||
hasAnimation(true),
|
||||
durationTime(500),
|
||||
hasSound(true),
|
||||
|
@ -64,16 +60,22 @@ GameController::GameController(GameScene & scene, QObject * parent) :
|
|||
scene.setBackgroundBrush(QColor(239, 239, 239));
|
||||
#endif /* MOBILE_APP_UI */
|
||||
|
||||
isAiPlayer[1] = false,
|
||||
isAiPlayer[2] = false,
|
||||
|
||||
ai[1] = new AiThread(1);
|
||||
ai[2] = new AiThread(2);
|
||||
|
||||
gameReset();
|
||||
|
||||
// 关联AI和控制器的着法命令行
|
||||
connect(&ai1, SIGNAL(command(const QString &, bool)),
|
||||
connect(ai[1], SIGNAL(command(const QString &, bool)),
|
||||
this, SLOT(command(const QString &, bool)));
|
||||
connect(&ai2, SIGNAL(command(const QString &, bool)),
|
||||
connect(ai[2], SIGNAL(command(const QString &, bool)),
|
||||
this, SLOT(command(const QString &, bool)));
|
||||
|
||||
// 关联AI和网络类的着法命令行
|
||||
connect(ai1.getClient(), SIGNAL(command(const QString &, bool)),
|
||||
connect(ai[1]->getClient(), SIGNAL(command(const QString &, bool)),
|
||||
this, SLOT(command(const QString &, bool)));
|
||||
|
||||
// 安装事件过滤器监视scene的各个事件,
|
||||
|
@ -88,10 +90,13 @@ GameController::~GameController()
|
|||
killTimer(timeID);
|
||||
|
||||
// 停掉线程
|
||||
ai1.stop();
|
||||
ai2.stop();
|
||||
ai1.wait();
|
||||
ai2.wait();
|
||||
ai[1]->stop();
|
||||
ai[2]->stop();
|
||||
ai[1]->wait();
|
||||
ai[2]->wait();
|
||||
|
||||
delete ai[1];
|
||||
delete ai[2];
|
||||
|
||||
#ifdef BOOK_LEARNING
|
||||
MillGameAi_ab::recordOpeningBookHashMapToFile();
|
||||
|
@ -149,10 +154,10 @@ void GameController::gameReset()
|
|||
|
||||
// 停掉线程
|
||||
if (!isAutoRestart) {
|
||||
ai1.stop();
|
||||
ai2.stop();
|
||||
isAiPlayer_1 = false;
|
||||
isAiPlayer_2 = false;
|
||||
ai[1]->stop();
|
||||
ai[2]->stop();
|
||||
isAiPlayer[1] = false;
|
||||
isAiPlayer[2] = false;
|
||||
}
|
||||
|
||||
// 清除棋子
|
||||
|
@ -206,10 +211,10 @@ void GameController::gameReset()
|
|||
// 如果规则不要求计时,则time1和time2表示已用时间
|
||||
if (timeLimit <= 0) {
|
||||
// 将玩家的已用时间清零
|
||||
remainingTime1 = remainingTime2 = 0;
|
||||
remainingTime[1] = remainingTime[2] = 0;
|
||||
} else {
|
||||
// 将玩家的剩余时间置为限定时间
|
||||
remainingTime1 = remainingTime2 = timeLimit * 60;
|
||||
remainingTime[1] = remainingTime[2] = timeLimit * 60;
|
||||
}
|
||||
|
||||
// 更新棋谱
|
||||
|
@ -219,7 +224,7 @@ void GameController::gameReset()
|
|||
currentRow = 0;
|
||||
|
||||
// 发出信号通知主窗口更新LCD显示
|
||||
QTime qtime = QTime(0, 0, 0, 0).addSecs(remainingTime1);
|
||||
QTime qtime = QTime(0, 0, 0, 0).addSecs(remainingTime[1]);
|
||||
emit time1Changed(qtime.toString("hh:mm:ss"));
|
||||
emit time2Changed(qtime.toString("hh:mm:ss"));
|
||||
|
||||
|
@ -228,8 +233,8 @@ void GameController::gameReset()
|
|||
emit statusBarChanged(message);
|
||||
|
||||
// 更新比分 LCD 显示
|
||||
emit score1Changed(QString::number(position_.score_1, 10));
|
||||
emit score2Changed(QString::number(position_.score_2, 10));
|
||||
emit score1Changed(QString::number(position_.score[1], 10));
|
||||
emit score2Changed(QString::number(position_.score[2], 10));
|
||||
emit scoreDrawChanged(QString::number(position_.score_draw, 10));
|
||||
|
||||
// 播放音效
|
||||
|
@ -282,64 +287,59 @@ void GameController::setRule(int ruleNo, step_t stepLimited /*= -1*/, int timeLi
|
|||
gameReset();
|
||||
}
|
||||
|
||||
void GameController::setEngine1(bool arg)
|
||||
void GameController::setEngine(int id, bool arg)
|
||||
{
|
||||
position_.configure(giveUpIfMostLose_, randomMove_);
|
||||
|
||||
isAiPlayer_1 = arg;
|
||||
isAiPlayer[id] = arg;
|
||||
|
||||
if (arg) {
|
||||
ai1.setAi(position_);
|
||||
if (ai1.isRunning())
|
||||
ai1.resume();
|
||||
ai[id]->setAi(position_);
|
||||
if (ai[id]->isRunning())
|
||||
ai[id]->resume();
|
||||
else
|
||||
ai1.start();
|
||||
ai[id]->start();
|
||||
} else {
|
||||
ai1.stop();
|
||||
ai[id]->stop();
|
||||
}
|
||||
}
|
||||
|
||||
void GameController::setEngine1(bool arg)
|
||||
{
|
||||
setEngine(1, arg);
|
||||
}
|
||||
|
||||
void GameController::setEngine2(bool arg)
|
||||
{
|
||||
position_.configure(giveUpIfMostLose_, randomMove_);
|
||||
|
||||
isAiPlayer_2 = arg;
|
||||
if (arg) {
|
||||
ai2.setAi(position_);
|
||||
if (ai2.isRunning())
|
||||
ai2.resume();
|
||||
else
|
||||
ai2.start();
|
||||
} else {
|
||||
ai2.stop();
|
||||
}
|
||||
setEngine(2, arg);
|
||||
}
|
||||
|
||||
void GameController::setAiDepthTime(depth_t depth1, int time1, depth_t depth2, int time2)
|
||||
{
|
||||
if (isAiPlayer_1) {
|
||||
ai1.stop();
|
||||
ai1.wait();
|
||||
if (isAiPlayer[1]) {
|
||||
ai[1]->stop();
|
||||
ai[1]->wait();
|
||||
}
|
||||
if (isAiPlayer_2) {
|
||||
ai2.stop();
|
||||
ai2.wait();
|
||||
if (isAiPlayer[2]) {
|
||||
ai[2]->stop();
|
||||
ai[2]->wait();
|
||||
}
|
||||
|
||||
ai1.setAi(position_, depth1, time1);
|
||||
ai2.setAi(position_, depth2, time2);
|
||||
ai[1]->setAi(position_, depth1, time1);
|
||||
ai[2]->setAi(position_, depth2, time2);
|
||||
|
||||
if (isAiPlayer_1) {
|
||||
ai1.start();
|
||||
if (isAiPlayer[1]) {
|
||||
ai[1]->start();
|
||||
}
|
||||
if (isAiPlayer_2) {
|
||||
ai2.start();
|
||||
if (isAiPlayer[2]) {
|
||||
ai[2]->start();
|
||||
}
|
||||
}
|
||||
|
||||
void GameController::getAiDepthTime(depth_t &depth1, int &time1, depth_t &depth2, int &time2)
|
||||
{
|
||||
ai1.getDepthTime(depth1, time1);
|
||||
ai2.getDepthTime(depth2, time2);
|
||||
ai[1]->getDepthTime(depth1, time1);
|
||||
ai[2]->getDepthTime(depth2, time2);
|
||||
}
|
||||
|
||||
void GameController::setAnimation(bool arg)
|
||||
|
@ -389,13 +389,13 @@ void GameController::setRandomMove(bool arg)
|
|||
// 上下翻转
|
||||
void GameController::flip()
|
||||
{
|
||||
if (isAiPlayer_1) {
|
||||
ai1.stop();
|
||||
ai1.wait();
|
||||
if (isAiPlayer[1]) {
|
||||
ai[1]->stop();
|
||||
ai[1]->wait();
|
||||
}
|
||||
if (isAiPlayer_2) {
|
||||
ai2.stop();
|
||||
ai2.wait();
|
||||
if (isAiPlayer[2]) {
|
||||
ai[2]->stop();
|
||||
ai[2]->wait();
|
||||
}
|
||||
|
||||
position_.context.board.mirror(position_.cmdlist, position_.cmdline, position_.move_, position_.currentRule, position_.currentLocation);
|
||||
|
@ -414,28 +414,28 @@ void GameController::flip()
|
|||
else
|
||||
phaseChange(currentRow, true);
|
||||
|
||||
ai1.setAi(position_);
|
||||
ai2.setAi(position_);
|
||||
ai[1]->setAi(position_);
|
||||
ai[2]->setAi(position_);
|
||||
|
||||
if (isAiPlayer_1) {
|
||||
ai1.start();
|
||||
if (isAiPlayer[1]) {
|
||||
ai[1]->start();
|
||||
}
|
||||
|
||||
if (isAiPlayer_2) {
|
||||
ai2.start();
|
||||
if (isAiPlayer[2]) {
|
||||
ai[2]->start();
|
||||
}
|
||||
}
|
||||
|
||||
// 左右镜像
|
||||
void GameController::mirror()
|
||||
{
|
||||
if (isAiPlayer_1) {
|
||||
ai1.stop();
|
||||
ai1.wait();
|
||||
if (isAiPlayer[1]) {
|
||||
ai[1]->stop();
|
||||
ai[1]->wait();
|
||||
}
|
||||
if (isAiPlayer_2) {
|
||||
ai2.stop();
|
||||
ai2.wait();
|
||||
if (isAiPlayer[2]) {
|
||||
ai[2]->stop();
|
||||
ai[2]->wait();
|
||||
}
|
||||
|
||||
position_.context.board.mirror(position_.cmdlist, position_.cmdline, position_.move_, position_.currentRule, position_.currentLocation);
|
||||
|
@ -456,28 +456,28 @@ void GameController::mirror()
|
|||
else
|
||||
phaseChange(currentRow, true);
|
||||
|
||||
ai1.setAi(position_);
|
||||
ai2.setAi(position_);
|
||||
ai[1]->setAi(position_);
|
||||
ai[2]->setAi(position_);
|
||||
|
||||
if (isAiPlayer_1) {
|
||||
ai1.start();
|
||||
if (isAiPlayer[1]) {
|
||||
ai[1]->start();
|
||||
}
|
||||
|
||||
if (isAiPlayer_2) {
|
||||
ai2.start();
|
||||
if (isAiPlayer[2]) {
|
||||
ai[2]->start();
|
||||
}
|
||||
}
|
||||
|
||||
// 视图须时针旋转90°
|
||||
void GameController::turnRight()
|
||||
{
|
||||
if (isAiPlayer_1) {
|
||||
ai1.stop();
|
||||
ai1.wait();
|
||||
if (isAiPlayer[1]) {
|
||||
ai[1]->stop();
|
||||
ai[1]->wait();
|
||||
}
|
||||
if (isAiPlayer_2) {
|
||||
ai2.stop();
|
||||
ai2.wait();
|
||||
if (isAiPlayer[2]) {
|
||||
ai[2]->stop();
|
||||
ai[2]->wait();
|
||||
}
|
||||
|
||||
position_.context.board.rotate(-90, position_.cmdlist, position_.cmdline, position_.move_, position_.currentRule, position_.currentLocation);
|
||||
|
@ -496,28 +496,28 @@ void GameController::turnRight()
|
|||
else
|
||||
phaseChange(currentRow, true);
|
||||
|
||||
ai1.setAi(position_);
|
||||
ai2.setAi(position_);
|
||||
ai[1]->setAi(position_);
|
||||
ai[2]->setAi(position_);
|
||||
|
||||
if (isAiPlayer_1) {
|
||||
ai1.start();
|
||||
if (isAiPlayer[1]) {
|
||||
ai[1]->start();
|
||||
}
|
||||
|
||||
if (isAiPlayer_2) {
|
||||
ai2.start();
|
||||
if (isAiPlayer[2]) {
|
||||
ai[2]->start();
|
||||
}
|
||||
}
|
||||
|
||||
// 视图逆时针旋转90°
|
||||
void GameController::turnLeft()
|
||||
{
|
||||
if (isAiPlayer_1) {
|
||||
ai1.stop();
|
||||
ai1.wait();
|
||||
if (isAiPlayer[1]) {
|
||||
ai[1]->stop();
|
||||
ai[1]->wait();
|
||||
}
|
||||
if (isAiPlayer_2) {
|
||||
ai2.stop();
|
||||
ai2.wait();
|
||||
if (isAiPlayer[2]) {
|
||||
ai[2]->stop();
|
||||
ai[2]->wait();
|
||||
}
|
||||
|
||||
position_.context.board.rotate(90, position_.cmdlist, position_.cmdline, position_.move_, position_.currentRule, position_.currentLocation);
|
||||
|
@ -532,13 +532,13 @@ void GameController::turnLeft()
|
|||
// 刷新显示
|
||||
updateScence();
|
||||
|
||||
ai1.setAi(position_);
|
||||
ai2.setAi(position_);
|
||||
if (isAiPlayer_1) {
|
||||
ai1.start();
|
||||
ai[1]->setAi(position_);
|
||||
ai[2]->setAi(position_);
|
||||
if (isAiPlayer[1]) {
|
||||
ai[1]->start();
|
||||
}
|
||||
if (isAiPlayer_2) {
|
||||
ai2.start();
|
||||
if (isAiPlayer[2]) {
|
||||
ai[2]->start();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -548,17 +548,17 @@ void GameController::timerEvent(QTimerEvent *event)
|
|||
static QTime qt1, qt2;
|
||||
|
||||
// 玩家的已用时间
|
||||
position_.getElapsedTime(remainingTime1, remainingTime2);
|
||||
position_.getElapsedTime(remainingTime[1], remainingTime[2]);
|
||||
|
||||
// 如果规则要求计时,则time1和time2表示倒计时
|
||||
if (timeLimit > 0) {
|
||||
// 玩家的剩余时间
|
||||
remainingTime1 = timeLimit * 60 - remainingTime1;
|
||||
remainingTime2 = timeLimit * 60 - remainingTime2;
|
||||
remainingTime[1] = timeLimit * 60 - remainingTime[1];
|
||||
remainingTime[2] = timeLimit * 60 - remainingTime[2];
|
||||
}
|
||||
|
||||
qt1 = QTime(0, 0, 0, 0).addSecs(remainingTime1);
|
||||
qt2 = QTime(0, 0, 0, 0).addSecs(remainingTime2);
|
||||
qt1 = QTime(0, 0, 0, 0).addSecs(remainingTime[1]);
|
||||
qt2 = QTime(0, 0, 0, 0).addSecs(remainingTime[2]);
|
||||
|
||||
emit time1Changed(qt1.toString("hh:mm:ss"));
|
||||
emit time2Changed(qt2.toString("hh:mm:ss"));
|
||||
|
@ -609,8 +609,7 @@ void GameController::timerEvent(QTimerEvent *event)
|
|||
|
||||
bool GameController::isAIsTurn()
|
||||
{
|
||||
return ((position_.whosTurn() == PLAYER_1 && isAiPlayer_1) ||
|
||||
(position_.whosTurn() == PLAYER_2 && isAiPlayer_2));
|
||||
return isAiPlayer[position_.context.turnId];
|
||||
}
|
||||
|
||||
// 关键槽函数,根据QGraphicsScene的信号和状态来执行选子、落子或去子
|
||||
|
@ -748,24 +747,24 @@ bool GameController::actionPiece(QPointF pos)
|
|||
if (&position_ == &(this->position_)) {
|
||||
// 如果还未决出胜负
|
||||
if (position_.whoWin() == PLAYER_NOBODY) {
|
||||
if (position_.whosTurn() == PLAYER_1) {
|
||||
if (isAiPlayer_1) {
|
||||
ai1.resume();
|
||||
if (position_.context.turn == PLAYER_1) {
|
||||
if (isAiPlayer[1]) {
|
||||
ai[1]->resume();
|
||||
}
|
||||
if (isAiPlayer_2)
|
||||
ai2.pause();
|
||||
if (isAiPlayer[2])
|
||||
ai[2]->pause();
|
||||
} else {
|
||||
if (isAiPlayer_1)
|
||||
ai1.pause();
|
||||
if (isAiPlayer_2) {
|
||||
ai2.resume();
|
||||
if (isAiPlayer[1])
|
||||
ai[1]->pause();
|
||||
if (isAiPlayer[2]) {
|
||||
ai[2]->resume();
|
||||
}
|
||||
}
|
||||
}
|
||||
// 如果已经决出胜负
|
||||
else {
|
||||
ai1.stop();
|
||||
ai2.stop();
|
||||
ai[1]->stop();
|
||||
ai[2]->stop();
|
||||
|
||||
// 弹框
|
||||
//message = QString::fromStdString(position_.getTips());
|
||||
|
@ -780,32 +779,28 @@ bool GameController::actionPiece(QPointF pos)
|
|||
|
||||
bool GameController::giveUp()
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
if (position_.whosTurn() == PLAYER_1) {
|
||||
result = position_.giveup(PLAYER_1);
|
||||
}
|
||||
else if (position_.whosTurn() == PLAYER_2) {
|
||||
result = position_.giveup(PLAYER_2);
|
||||
}
|
||||
bool result = position_.giveup(position_.context.turn);
|
||||
|
||||
if (result) {
|
||||
// 将新增的棋谱行插入到ListModel
|
||||
currentRow = manualListModel.rowCount() - 1;
|
||||
int k = 0;
|
||||
|
||||
// 输出命令行
|
||||
for (const auto & i : *(position_.getCmdList())) {
|
||||
// 跳过已添加的,因标准list容器没有下标
|
||||
if (k++ <= currentRow)
|
||||
continue;
|
||||
manualListModel.insertRow(++currentRow);
|
||||
manualListModel.setData(manualListModel.index(currentRow), i.c_str());
|
||||
}
|
||||
if (position_.whoWin() != PLAYER_NOBODY)
|
||||
playSound(":/sound/resources/sound/loss.wav");
|
||||
if (!result) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 将新增的棋谱行插入到ListModel
|
||||
currentRow = manualListModel.rowCount() - 1;
|
||||
int k = 0;
|
||||
|
||||
// 输出命令行
|
||||
for (const auto & i : *(position_.getCmdList())) {
|
||||
// 跳过已添加的,因标准list容器没有下标
|
||||
if (k++ <= currentRow)
|
||||
continue;
|
||||
manualListModel.insertRow(++currentRow);
|
||||
manualListModel.setData(manualListModel.index(currentRow), i.c_str());
|
||||
}
|
||||
|
||||
if (position_.whoWin() != PLAYER_NOBODY)
|
||||
playSound(":/sound/resources/sound/loss.wav");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -815,10 +810,10 @@ bool GameController::command(const QString &cmd, bool update /* = true */)
|
|||
Q_UNUSED(hasSound)
|
||||
|
||||
// 防止接收滞后结束的线程发送的指令
|
||||
if (sender() == &ai1 && !isAiPlayer_1)
|
||||
if (sender() == ai[1] && !isAiPlayer[1])
|
||||
return false;
|
||||
|
||||
if (sender() == &ai2 && !isAiPlayer_2)
|
||||
if (sender() == ai[2] && !isAiPlayer[2])
|
||||
return false;
|
||||
|
||||
// 声音
|
||||
|
@ -892,34 +887,34 @@ bool GameController::command(const QString &cmd, bool update /* = true */)
|
|||
if (&position_ == &(this->position_)) {
|
||||
// 如果还未决出胜负
|
||||
if (position_.whoWin() == PLAYER_NOBODY) {
|
||||
if (position_.whosTurn() == PLAYER_1) {
|
||||
if (isAiPlayer_1) {
|
||||
ai1.resume();
|
||||
if (position_.context.turn == PLAYER_1) {
|
||||
if (isAiPlayer[1]) {
|
||||
ai[1]->resume();
|
||||
}
|
||||
if (isAiPlayer_2)
|
||||
ai2.pause();
|
||||
if (isAiPlayer[2])
|
||||
ai[2]->pause();
|
||||
} else {
|
||||
if (isAiPlayer_1)
|
||||
ai1.pause();
|
||||
if (isAiPlayer_2) {
|
||||
ai2.resume();
|
||||
if (isAiPlayer[1])
|
||||
ai[1]->pause();
|
||||
if (isAiPlayer[2]) {
|
||||
ai[2]->resume();
|
||||
}
|
||||
}
|
||||
}
|
||||
// 如果已经决出胜负
|
||||
else {
|
||||
ai1.stop();
|
||||
ai2.stop();
|
||||
ai[1]->stop();
|
||||
ai[2]->stop();
|
||||
|
||||
if (isAutoRestart) {
|
||||
gameReset();
|
||||
gameStart();
|
||||
|
||||
if (isAiPlayer_1) {
|
||||
setEngine1(true);
|
||||
if (isAiPlayer[1]) {
|
||||
setEngine(1, true);
|
||||
}
|
||||
if (isAiPlayer_2) {
|
||||
setEngine2(true);
|
||||
if (isAiPlayer[2]) {
|
||||
setEngine(2, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -932,11 +927,11 @@ bool GameController::command(const QString &cmd, bool update /* = true */)
|
|||
}
|
||||
|
||||
// 网络: 将着法放到服务器的发送列表中
|
||||
if (isAiPlayer_1)
|
||||
if (isAiPlayer[1])
|
||||
{
|
||||
ai1.getServer()->setAction(cmd);
|
||||
} else if (isAiPlayer_2) {
|
||||
ai1.getServer()->setAction(cmd); // 注意: 同样是AI1
|
||||
ai[1]->getServer()->setAction(cmd);
|
||||
} else if (isAiPlayer[2]) {
|
||||
ai[1]->getServer()->setAction(cmd); // 注意: 同样是AI1
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -1106,8 +1101,8 @@ bool GameController::updateScence(Position &game)
|
|||
animationGroup->start(QAbstractAnimation::DeleteWhenStopped);
|
||||
|
||||
// 更新比分 LCD 显示
|
||||
emit score1Changed(QString::number(game.score_1, 10));
|
||||
emit score2Changed(QString::number(game.score_2, 10));
|
||||
emit score1Changed(QString::number(game.score[1], 10));
|
||||
emit score2Changed(QString::number(game.score[2], 10));
|
||||
emit scoreDrawChanged(QString::number(game.score_draw, 10));
|
||||
|
||||
return true;
|
||||
|
@ -1115,6 +1110,6 @@ bool GameController::updateScence(Position &game)
|
|||
|
||||
void GameController::showNetworkWindow()
|
||||
{
|
||||
ai1.getServer()->show();
|
||||
ai1.getClient()->show();
|
||||
ai[1]->getServer()->show();
|
||||
ai[1]->getClient()->show();
|
||||
}
|
||||
|
|
|
@ -140,11 +140,10 @@ public slots:
|
|||
// 设置黑白反转状态
|
||||
void setInvert(bool arg = true);
|
||||
|
||||
// 让电脑执先手
|
||||
void setEngine1(bool arg = true);
|
||||
|
||||
// 让电脑执后手
|
||||
void setEngine2(bool arg = true);
|
||||
// id为1时让电脑执先手, id为2时让的电脑执后手
|
||||
void setEngine(int id, bool arg = true);
|
||||
void setEngine1(bool arg);
|
||||
void setEngine2(bool arg);
|
||||
|
||||
// 是否有落子动画
|
||||
void setAnimation(bool arg = true);
|
||||
|
@ -210,7 +209,7 @@ private:
|
|||
Position dummyPosition;
|
||||
|
||||
// 2个AI的线程
|
||||
AiThread ai1, ai2;
|
||||
AiThread *ai[3];
|
||||
|
||||
// 棋局的场景类
|
||||
GameScene &scene;
|
||||
|
@ -230,11 +229,8 @@ private:
|
|||
// 是否黑白反转
|
||||
bool isInverted;
|
||||
|
||||
// 是否电脑执先手
|
||||
bool isAiPlayer_1;
|
||||
|
||||
// 是否电脑执后手
|
||||
bool isAiPlayer_2;
|
||||
// 电脑执先手时为 true
|
||||
bool isAiPlayer[3];
|
||||
|
||||
// 是否有落子动画
|
||||
bool hasAnimation;
|
||||
|
@ -266,11 +262,8 @@ private:
|
|||
// 规则限步数
|
||||
step_t stepsLimit;
|
||||
|
||||
// 玩家1剩余时间(秒)
|
||||
time_t remainingTime1;
|
||||
|
||||
// 玩家2剩余时间(秒)
|
||||
time_t remainingTime2;
|
||||
// 玩家剩余时间(秒)
|
||||
time_t remainingTime[3];
|
||||
|
||||
// 用于主窗口状态栏显示的字符串
|
||||
QString message;
|
||||
|
|
Loading…
Reference in New Issue