refactor: 使用 position 表示"局面"的意思

相关文件名暂未修改.
This commit is contained in:
CalciteM Team 2019-09-13 00:23:24 +08:00
parent 4b4c754050
commit 073f4ffa01
14 changed files with 299 additions and 299 deletions

View File

@ -21,7 +21,7 @@
#include "evaluate.h"
value_t Evaluation::getValue(MillGame &gameTemp, GameContext *gameContext, MillGameAi_ab::Node *node)
value_t Evaluation::getValue(Position &dummyPosition, PositionContext *positionContext, MillGameAi_ab::Node *node)
{
// 初始评估值为0对先手有利则增大对后手有利则减小
value_t value = 0;
@ -31,31 +31,31 @@ value_t Evaluation::getValue(MillGame &gameTemp, GameContext *gameContext, MillG
int nPiecesNeedRemove = 0;
#ifdef DEBUG_AB_TREE
node->stage = gameContext->stage;
node->action = gameContext->action;
node->stage = positionContext->stage;
node->action = positionContext->action;
node->evaluated = true;
#endif
switch (gameContext->stage) {
switch (positionContext->stage) {
case GAME_NOTSTARTED:
break;
case GAME_PLACING:
// 按手中的棋子计分不要break;
nPiecesInHandDiff = gameContext->nPiecesInHand_1 - gameContext->nPiecesInHand_2;
nPiecesInHandDiff = positionContext->nPiecesInHand_1 - positionContext->nPiecesInHand_2;
value += nPiecesInHandDiff * 50;
#ifdef DEBUG_AB_TREE
node->nPiecesInHandDiff = nPiecesInHandDiff;
#endif
// 按场上棋子计分
nPiecesOnBoardDiff = gameContext->nPiecesOnBoard_1 - gameContext->nPiecesOnBoard_2;
nPiecesOnBoardDiff = positionContext->nPiecesOnBoard_1 - positionContext->nPiecesOnBoard_2;
value += nPiecesOnBoardDiff * 100;
#ifdef DEBUG_AB_TREE
node->nPiecesOnBoardDiff = nPiecesOnBoardDiff;
#endif
switch (gameContext->action) {
switch (positionContext->action) {
// 选子和落子使用相同的评价方法
case ACTION_CHOOSE:
case ACTION_PLACE:
@ -63,8 +63,8 @@ value_t Evaluation::getValue(MillGame &gameTemp, GameContext *gameContext, MillG
// 如果形成去子状态每有一个可去的子算100分
case ACTION_CAPTURE:
nPiecesNeedRemove = (gameContext->turn == PLAYER1) ?
gameContext->nPiecesNeedRemove : -(gameContext->nPiecesNeedRemove);
nPiecesNeedRemove = (positionContext->turn == PLAYER1) ?
positionContext->nPiecesNeedRemove : -(positionContext->nPiecesNeedRemove);
value += nPiecesNeedRemove * 100;
#ifdef DEBUG_AB_TREE
node->nPiecesNeedRemove = nPiecesNeedRemove;
@ -78,14 +78,14 @@ value_t Evaluation::getValue(MillGame &gameTemp, GameContext *gameContext, MillG
case GAME_MOVING:
// 按场上棋子计分
value += gameContext->nPiecesOnBoard_1 * 100 - gameContext->nPiecesOnBoard_2 * 100;
value += positionContext->nPiecesOnBoard_1 * 100 - positionContext->nPiecesOnBoard_2 * 100;
#ifdef EVALUATE_MOBILITY
// 按棋子活动能力计分
value += gameTemp.getMobilityDiff(gameContext->turn, gameTemp.currentRule, gameContext->nPiecesInHand_1, gameContext->nPiecesInHand_2, false) * 10;
value += dummyPosition.getMobilityDiff(positionContext->turn, dummyPosition.currentRule, positionContext->nPiecesInHand_1, positionContext->nPiecesInHand_2, false) * 10;
#endif /* EVALUATE_MOBILITY */
switch (gameContext->action) {
switch (positionContext->action) {
// 选子和落子使用相同的评价方法
case ACTION_CHOOSE:
case ACTION_PLACE:
@ -93,8 +93,8 @@ value_t Evaluation::getValue(MillGame &gameTemp, GameContext *gameContext, MillG
// 如果形成去子状态每有一个可去的子算128分
case ACTION_CAPTURE:
nPiecesNeedRemove = (gameContext->turn == PLAYER1) ?
gameContext->nPiecesNeedRemove : -(gameContext->nPiecesNeedRemove);
nPiecesNeedRemove = (positionContext->turn == PLAYER1) ?
positionContext->nPiecesNeedRemove : -(positionContext->nPiecesNeedRemove);
value += nPiecesNeedRemove * 128;
#ifdef DEBUG_AB_TREE
node->nPiecesNeedRemove = nPiecesNeedRemove;
@ -109,9 +109,9 @@ value_t Evaluation::getValue(MillGame &gameTemp, GameContext *gameContext, MillG
// 终局评价最简单
case GAME_OVER:
// 布局阶段闷棋判断
if (gameContext->nPiecesOnBoard_1 + gameContext->nPiecesOnBoard_2 >=
if (positionContext->nPiecesOnBoard_1 + positionContext->nPiecesOnBoard_2 >=
Board::N_SEATS * Board::N_RINGS) {
if (gameTemp.getRule()->isStartingPlayerLoseWhenBoardFull) {
if (dummyPosition.getRule()->isStartingPlayerLoseWhenBoardFull) {
// winner = PLAYER2;
value -= 10000;
#ifdef DEBUG_AB_TREE
@ -123,11 +123,11 @@ value_t Evaluation::getValue(MillGame &gameTemp, GameContext *gameContext, MillG
}
// 走棋阶段被闷判断
if (gameContext->action == ACTION_CHOOSE &&
gameTemp.context.board.isAllSurrounded(gameContext->turn, gameTemp.currentRule, gameContext->nPiecesOnBoard_1, gameContext->nPiecesOnBoard_2, gameContext->turn) &&
gameTemp.getRule()->isLoseWhenNoWay) {
if (positionContext->action == ACTION_CHOOSE &&
dummyPosition.context.board.isAllSurrounded(positionContext->turn, dummyPosition.currentRule, positionContext->nPiecesOnBoard_1, positionContext->nPiecesOnBoard_2, positionContext->turn) &&
dummyPosition.getRule()->isLoseWhenNoWay) {
// 规则要求被“闷”判负,则对手获胜
if (gameContext->turn == PLAYER1) {
if (positionContext->turn == PLAYER1) {
value -= 10000;
#ifdef DEBUG_AB_TREE
node->result = -2;
@ -141,12 +141,12 @@ value_t Evaluation::getValue(MillGame &gameTemp, GameContext *gameContext, MillG
}
// 剩余棋子个数判断
if (gameContext->nPiecesOnBoard_1 < gameTemp.getRule()->nPiecesAtLeast) {
if (positionContext->nPiecesOnBoard_1 < dummyPosition.getRule()->nPiecesAtLeast) {
value -= 10000;
#ifdef DEBUG_AB_TREE
node->result = -1;
#endif
} else if (gameContext->nPiecesOnBoard_2 < gameTemp.getRule()->nPiecesAtLeast) {
} else if (positionContext->nPiecesOnBoard_2 < dummyPosition.getRule()->nPiecesAtLeast) {
value += 10000;
#ifdef DEBUG_AB_TREE
node->result = 1;

View File

@ -34,7 +34,7 @@ public:
Evaluation &operator=(const Evaluation &) = delete;
static value_t getValue(MillGame &gameTemp, GameContext *gameContext, MillGameAi_ab::Node *node);
static value_t getValue(Position &dummyPosition, PositionContext *positionContext, MillGameAi_ab::Node *node);
// 评估子力
#ifdef EVALUATE_ENABLE

View File

@ -23,7 +23,7 @@
#include "movegen.h"
void MoveList::generateLegalMoves(MillGameAi_ab &ai_ab, MillGame &gameTemp,
void MoveList::generateLegalMoves(MillGameAi_ab &ai_ab, Position &dummyPosition,
MillGameAi_ab::Node *node, MillGameAi_ab::Node *rootNode,
move_t bestMove)
{
@ -32,23 +32,23 @@ void MoveList::generateLegalMoves(MillGameAi_ab &ai_ab, MillGame &gameTemp,
size_t newCapacity = 24;
// 留足余量空间避免多次重新分配,此动作本身也占用 CPU/内存 开销
switch (gameTemp.getStage()) {
switch (dummyPosition.getStage()) {
case GAME_PLACING:
if (gameTemp.getAction() == ACTION_CAPTURE) {
if (gameTemp.whosTurn() == PLAYER1)
newCapacity = static_cast<size_t>(gameTemp.getPiecesOnBoardCount_2());
if (dummyPosition.getAction() == ACTION_CAPTURE) {
if (dummyPosition.whosTurn() == PLAYER1)
newCapacity = static_cast<size_t>(dummyPosition.getPiecesOnBoardCount_2());
else
newCapacity = static_cast<size_t>(gameTemp.getPiecesOnBoardCount_1());
newCapacity = static_cast<size_t>(dummyPosition.getPiecesOnBoardCount_1());
} else {
newCapacity = static_cast<size_t>(gameTemp.getPiecesInHandCount_1() + gameTemp.getPiecesInHandCount_2());
newCapacity = static_cast<size_t>(dummyPosition.getPiecesInHandCount_1() + dummyPosition.getPiecesInHandCount_2());
}
break;
case GAME_MOVING:
if (gameTemp.getAction() == ACTION_CAPTURE) {
if (gameTemp.whosTurn() == PLAYER1)
newCapacity = static_cast<size_t>(gameTemp.getPiecesOnBoardCount_2());
if (dummyPosition.getAction() == ACTION_CAPTURE) {
if (dummyPosition.whosTurn() == PLAYER1)
newCapacity = static_cast<size_t>(dummyPosition.getPiecesOnBoardCount_2());
else
newCapacity = static_cast<size_t>(gameTemp.getPiecesOnBoardCount_1());
newCapacity = static_cast<size_t>(dummyPosition.getPiecesOnBoardCount_1());
} else {
newCapacity = 6;
}
@ -69,28 +69,28 @@ void MoveList::generateLegalMoves(MillGameAi_ab &ai_ab, MillGame &gameTemp,
}
// 对手
Player opponent = MillGame::getOpponent(gameTemp.context.turn);
Player opponent = Position::getOpponent(dummyPosition.context.turn);
// 列出所有合法的下一招
switch (gameTemp.context.action) {
switch (dummyPosition.context.action) {
// 对于选子和落子动作
case ACTION_CHOOSE:
case ACTION_PLACE:
// 对于摆子阶段
if (gameTemp.context.stage & (GAME_PLACING | GAME_NOTSTARTED)) {
if (dummyPosition.context.stage & (GAME_PLACING | GAME_NOTSTARTED)) {
for (int i : movePriorityTable) {
location = i;
if (gameTemp.board_[location]) {
if (dummyPosition.board_[location]) {
continue;
}
if (gameTemp.context.stage != GAME_NOTSTARTED || node != rootNode) {
ai_ab.addNode(node, 0, location, bestMove, gameTemp.context.turn);
if (dummyPosition.context.stage != GAME_NOTSTARTED || node != rootNode) {
ai_ab.addNode(node, 0, location, bestMove, dummyPosition.context.turn);
} else {
// 若为先手,则抢占星位
if (MillGame::isStarPoint(location)) {
ai_ab.addNode(node, MillGameAi_ab::INF_VALUE, location, bestMove, gameTemp.context.turn);
if (Position::isStarPoint(location)) {
ai_ab.addNode(node, MillGameAi_ab::INF_VALUE, location, bestMove, dummyPosition.context.turn);
}
}
}
@ -98,36 +98,36 @@ void MoveList::generateLegalMoves(MillGameAi_ab &ai_ab, MillGame &gameTemp,
}
// 对于移子阶段
if (gameTemp.context.stage & GAME_MOVING) {
if (dummyPosition.context.stage & GAME_MOVING) {
int newLocation, oldLocation;
// 尽量走理论上较差的位置的棋子
for (int i = MOVE_PRIORITY_TABLE_SIZE - 1; i >= 0; i--) {
oldLocation = movePriorityTable[i];
if (!gameTemp.choose(oldLocation)) {
if (!dummyPosition.choose(oldLocation)) {
continue;
}
if ((gameTemp.context.turn == PLAYER1 &&
(gameTemp.context.nPiecesOnBoard_1 > gameTemp.currentRule.nPiecesAtLeast || !gameTemp.currentRule.allowFlyWhenRemainThreePieces)) ||
(gameTemp.context.turn == PLAYER2 &&
(gameTemp.context.nPiecesOnBoard_2 > gameTemp.currentRule.nPiecesAtLeast || !gameTemp.currentRule.allowFlyWhenRemainThreePieces))) {
if ((dummyPosition.context.turn == PLAYER1 &&
(dummyPosition.context.nPiecesOnBoard_1 > dummyPosition.currentRule.nPiecesAtLeast || !dummyPosition.currentRule.allowFlyWhenRemainThreePieces)) ||
(dummyPosition.context.turn == PLAYER2 &&
(dummyPosition.context.nPiecesOnBoard_2 > dummyPosition.currentRule.nPiecesAtLeast || !dummyPosition.currentRule.allowFlyWhenRemainThreePieces))) {
// 对于棋盘上还有3个子以上或不允许飞子的情况要求必须在着法表中
for (int moveDirection = MOVE_DIRECTION_CLOCKWISE; moveDirection <= MOVE_DIRECTION_OUTWARD; moveDirection++) {
// 对于原有位置,遍历四个方向的着法,如果棋盘上为空位就加到结点列表中
newLocation = moveTable[oldLocation][moveDirection];
if (newLocation && !gameTemp.board_[newLocation]) {
if (newLocation && !dummyPosition.board_[newLocation]) {
int move = (oldLocation << 8) + newLocation;
ai_ab.addNode(node, 0, move, bestMove, gameTemp.context.turn); // (12%)
ai_ab.addNode(node, 0, move, bestMove, dummyPosition.context.turn); // (12%)
}
}
} else {
// 对于棋盘上还有不到3个字但允许飞子的情况不要求在着法表中是空位就行
for (newLocation = Board::LOCATION_BEGIN; newLocation < Board::LOCATION_END; newLocation++) {
if (!gameTemp.board_[newLocation]) {
if (!dummyPosition.board_[newLocation]) {
int move = (oldLocation << 8) + newLocation;
ai_ab.addNode(node, 0, move, bestMove, gameTemp.context.turn);
ai_ab.addNode(node, 0, move, bestMove, dummyPosition.context.turn);
}
}
}
@ -137,12 +137,12 @@ void MoveList::generateLegalMoves(MillGameAi_ab &ai_ab, MillGame &gameTemp,
// 对于吃子动作
case ACTION_CAPTURE:
if (gameTemp.context.board.isAllInMills(opponent)) {
if (dummyPosition.context.board.isAllInMills(opponent)) {
// 全成三的情况
for (int i = MOVE_PRIORITY_TABLE_SIZE - 1; i >= 0; i--) {
location = movePriorityTable[i];
if (gameTemp.board_[location] & opponent) {
ai_ab.addNode(node, 0, -location, bestMove, gameTemp.context.turn);
if (dummyPosition.board_[location] & opponent) {
ai_ab.addNode(node, 0, -location, bestMove, dummyPosition.context.turn);
}
}
break;
@ -151,9 +151,9 @@ void MoveList::generateLegalMoves(MillGameAi_ab &ai_ab, MillGame &gameTemp,
// 不是全成三的情况
for (int i = MOVE_PRIORITY_TABLE_SIZE - 1; i >= 0; i--) {
location = movePriorityTable[i];
if (gameTemp.board_[location] & opponent) {
if (gameTemp.getRule()->allowRemoveMill || !gameTemp.context.board.inHowManyMills(location)) {
ai_ab.addNode(node, 0, -location, bestMove, gameTemp.context.turn);
if (dummyPosition.board_[location] & opponent) {
if (dummyPosition.getRule()->allowRemoveMill || !dummyPosition.context.board.inHowManyMills(location)) {
ai_ab.addNode(node, 0, -location, bestMove, dummyPosition.context.turn);
}
}
}
@ -164,7 +164,7 @@ void MoveList::generateLegalMoves(MillGameAi_ab &ai_ab, MillGame &gameTemp,
}
}
void MoveList::createMoveTable(MillGame &game)
void MoveList::createMoveTable(Position &position)
{
#if 1
const int moveTable_obliqueLine[Board::N_LOCATIONS][N_MOVE_DIRECTIONS] = {
@ -356,7 +356,7 @@ void MoveList::createMoveTable(MillGame &game)
};
#endif
if (game.currentRule.hasObliqueLines) {
if (position.currentRule.hasObliqueLines) {
memcpy(moveTable, moveTable_obliqueLine, sizeof(moveTable));
} else {
memcpy(moveTable, moveTable_noObliqueLine, sizeof(moveTable));
@ -379,14 +379,14 @@ void MoveList::createMoveTable(MillGame &game)
#endif
}
void MoveList::shuffleMovePriorityTable(MillGame & game)
void MoveList::shuffleMovePriorityTable(Position &position)
{
array<int, 4> movePriorityTable0 = { 17, 19, 21, 23 }; // 中圈四个顶点 (星位)
array<int, 8> movePriorityTable1 = { 25, 27, 29, 31, 9, 11, 13, 15 }; // 外圈和内圈四个顶点
array<int, 4> movePriorityTable2 = { 16, 18, 20, 22 }; // 中圈十字架
array<int, 8> movePriorityTable3 = { 24, 26, 28, 30, 8, 10, 12, 14 }; // 外内圈十字架
if (game.getRandomMove() == true) {
if (position.getRandomMove() == true) {
uint32_t seed = static_cast<uint32_t>(std::chrono::system_clock::now().time_since_epoch().count());
std::shuffle(movePriorityTable0.begin(), movePriorityTable0.end(), std::default_random_engine(seed));

View File

@ -34,15 +34,15 @@ public:
MoveList &operator=(const MoveList &) = delete;
// 生成所有合法的着法并建立子节点
static void generateLegalMoves(MillGameAi_ab &ai_ab, MillGame &gameTemp,
static void generateLegalMoves(MillGameAi_ab &ai_ab, Position &dummyPosition,
MillGameAi_ab::Node *node, MillGameAi_ab::Node *rootNode,
move_t bestMove);
// 生成着法表
static void createMoveTable(MillGame &game);
static void createMoveTable(Position &position);
// 随机打乱着法搜索顺序
static void shuffleMovePriorityTable(MillGame &game);
static void shuffleMovePriorityTable(Position &position);
// 着法表 // TODO: Move to private
inline static int moveTable[Board::N_LOCATIONS][N_MOVE_DIRECTIONS] = { {0} };

View File

@ -57,7 +57,7 @@ depth_t MillGameAi_ab::changeDepth(depth_t originalDepth)
{
depth_t newDepth = originalDepth;
if ((gameTemp.context.stage) & (GAME_PLACING)) {
if ((dummyPosition.context.stage) & (GAME_PLACING)) {
#ifdef GAME_PLACING_DYNAMIC_DEPTH
#ifdef DEAL_WITH_HORIZON_EFFECT
#ifdef TRANSPOSITION_TABLE_ENABLE
@ -77,7 +77,7 @@ depth_t MillGameAi_ab::changeDepth(depth_t originalDepth)
depth_t depthTable[] = { 2, 13, 13, 13, 12, 11, 10, 9, 9, 8, 8, 7, 1 };
#endif
#endif // DEAL_WITH_HORIZON_EFFECT
newDepth = depthTable[gameTemp.getPiecesInHandCount_1()];
newDepth = depthTable[dummyPosition.getPiecesInHandCount_1()];
#elif defined GAME_PLACING_FIXED_DEPTH
newDepth = GAME_PLACING_FIXED_DEPTH;
#endif // GAME_PLACING_DYNAMIC_DEPTH
@ -85,7 +85,7 @@ depth_t MillGameAi_ab::changeDepth(depth_t originalDepth)
#ifdef GAME_MOVING_FIXED_DEPTH
// 走棋阶段将深度调整
if ((gameTemp.context.stage) & (GAME_MOVING)) {
if ((dummyPosition.context.stage) & (GAME_MOVING)) {
newDepth = GAME_MOVING_FIXED_DEPTH;
}
#endif /* GAME_MOVING_FIXED_DEPTH */
@ -141,8 +141,8 @@ struct MillGameAi_ab::Node *MillGameAi_ab::addNode(
#ifdef DEBUG_AB_TREE
newNode->root = rootNode;
newNode->stage = gameTemp.context.stage;
newNode->action = gameTemp.context.action;
newNode->stage = dummyPosition.context.stage;
newNode->action = dummyPosition.context.action;
newNode->evaluated = false;
newNode->nPiecesInHandDiff = INT_MAX;
newNode->nPiecesOnBoardDiff = INT_MAX;
@ -156,15 +156,15 @@ struct MillGameAi_ab::Node *MillGameAi_ab::addNode(
char cmd[32] = { 0 };
if (move < 0) {
gameTemp.context.board.locationToPolar(-move, r, s);
dummyPosition.context.board.locationToPolar(-move, r, s);
sprintf(cmd, "-(%1u,%1u)", r, s);
} else if (move & 0x7f00) {
int r1, s1;
gameTemp.context.board.locationToPolar(move >> 8, r1, s1);
gameTemp.context.board.locationToPolar(move & 0x00ff, r, s);
dummyPosition.context.board.locationToPolar(move >> 8, r1, s1);
dummyPosition.context.board.locationToPolar(move & 0x00ff, r, s);
sprintf(cmd, "(%1u,%1u)->(%1u,%1u)", r1, s1, r, s);
} else {
gameTemp.context.board.locationToPolar(move & 0x007f, r, s);
dummyPosition.context.board.locationToPolar(move & 0x007f, r, s);
sprintf(cmd, "(%1u,%1u)", r, s);
}
@ -176,7 +176,7 @@ struct MillGameAi_ab::Node *MillGameAi_ab::addNode(
if (bestMove == 0 || move != bestMove) {
#ifdef MILL_FIRST
// 优先成三
if (gameTemp.getStage() == GAME_PLACING && move > 0 && gameTemp.context.board.isInMills(move, true)) {
if (dummyPosition.getStage() == GAME_PLACING && move > 0 && dummyPosition.context.board.isInMills(move, true)) {
parent->children.insert(parent->children.begin(), newNode);
} else {
parent->children.push_back(newNode);
@ -233,7 +233,7 @@ void MillGameAi_ab::sortLegalMoves(Node *node)
{
// 这个函数对效率的影响很大,排序好的话,剪枝较早,节省时间,但不能在此函数耗费太多时间
if (gameTemp.whosTurn() == PLAYER1) {
if (dummyPosition.whosTurn() == PLAYER1) {
std::stable_sort(node->children.begin(), node->children.end(), nodeGreater);
} else {
std::stable_sort(node->children.begin(), node->children.end(), nodeLess);
@ -260,10 +260,10 @@ void MillGameAi_ab::deleteTree(Node *node)
#endif
}
void MillGameAi_ab::setGame(const MillGame &game)
void MillGameAi_ab::setPosition(const Position &position)
{
// 如果规则改变重建hashmap
if (strcmp(this->game_.currentRule.name, game.currentRule.name) != 0) {
if (strcmp(this->position_.currentRule.name, position.currentRule.name) != 0) {
#ifdef TRANSPOSITION_TABLE_ENABLE
TranspositionTable::clearTranspositionTable();
#endif // TRANSPOSITION_TABLE_ENABLE
@ -277,9 +277,9 @@ void MillGameAi_ab::setGame(const MillGame &game)
positions.clear();
}
this->game_ = game;
gameTemp = game;
gameContext = &(gameTemp.context);
this->position_ = position;
dummyPosition = position;
positionContext = &(dummyPosition.context);
requiredQuit = false;
deleteTree(rootNode);
#ifdef MEMORY_POOL
@ -313,11 +313,11 @@ int MillGameAi_ab::alphaBetaPruning(depth_t depth)
chrono::steady_clock::time_point timeEnd;
#ifdef BOOK_LEARNING
if (game_.getStage() == GAME_PLACING)
if (position_.getStage() == GAME_PLACING)
{
if (game_.context.nPiecesInHand_1 <= 10) {
if (position_.context.nPiecesInHand_1 <= 10) {
// 开局库只记录摆棋阶段最后的局面
openingBook.push_back(game_.getHash());
openingBook.push_back(position_.getHash());
} else {
// 暂时在此处清空开局库
openingBook.clear();
@ -328,8 +328,8 @@ int MillGameAi_ab::alphaBetaPruning(depth_t depth)
#ifdef THREEFOLD_REPETITION
static int nRepetition = 0;
if (game_.getStage() == GAME_MOVING) {
hash_t hash = game_.getHash();
if (position_.getStage() == GAME_MOVING) {
hash_t hash = position_.getHash();
if (std::find(positions.begin(), positions.end(), hash) != positions.end()) {
nRepetition++;
@ -342,13 +342,13 @@ int MillGameAi_ab::alphaBetaPruning(depth_t depth)
}
}
if (game_.getStage() == GAME_PLACING) {
if (position_.getStage() == GAME_PLACING) {
positions.clear();
}
#endif // THREEFOLD_REPETITION
// 随机打乱着法顺序
MoveList::shuffleMovePriorityTable(game_);
MoveList::shuffleMovePriorityTable(position_);
#ifdef IDS_SUPPORT
// 深化迭代
@ -404,7 +404,7 @@ value_t MillGameAi_ab::alphaBetaPruning(depth_t depth, value_t alpha, value_t be
enum TranspositionTable::HashType hashf = TranspositionTable::hashfALPHA;
// 获取哈希值
hash_t hash = gameTemp.getHash();
hash_t hash = dummyPosition.getHash();
#ifdef DEBUG_AB_TREE
node->hash = hash;
#endif
@ -432,7 +432,7 @@ value_t MillGameAi_ab::alphaBetaPruning(depth_t depth, value_t alpha, value_t be
#if 0
// TODO: 有必要针对深度微调 value?
if (gameContext->turn == PLAYER1)
if (positionContext->turn == PLAYER1)
node->value += hashValue.depth - depth;
else
node->value -= hashValue.depth - depth;
@ -447,7 +447,7 @@ value_t MillGameAi_ab::alphaBetaPruning(depth_t depth, value_t alpha, value_t be
#ifdef DEBUG_AB_TREE
node->depth = depth;
node->root = rootNode;
// node->player = gameContext->turn;
// node->player = positionContext->turn;
// 初始化
node->isLeaf = false;
node->isTimeout = false;
@ -459,9 +459,9 @@ value_t MillGameAi_ab::alphaBetaPruning(depth_t depth, value_t alpha, value_t be
#endif // DEBUG_AB_TREE
// 搜索到叶子节点(决胜局面) // TODO: 对哈希进行特殊处理
if (gameContext->stage == GAME_OVER) {
if (positionContext->stage == GAME_OVER) {
// 局面评估
node->value = Evaluation::getValue(gameTemp, gameContext, node);
node->value = Evaluation::getValue(dummyPosition, positionContext, node);
evaluatedNodeCount++;
// 为争取速胜value 值 +- 深度
@ -486,11 +486,11 @@ value_t MillGameAi_ab::alphaBetaPruning(depth_t depth, value_t alpha, value_t be
// 搜索到第0层或需要退出
if (!depth || requiredQuit) {
// 局面评估
node->value = Evaluation::getValue(gameTemp, gameContext, node);
node->value = Evaluation::getValue(dummyPosition, positionContext, node);
evaluatedNodeCount++;
// 为争取速胜value 值 +- 深度 (有必要?)
if (gameContext->turn == PLAYER1) {
if (positionContext->turn == PLAYER1) {
node->value += depth;
} else {
node->value -= depth;
@ -504,8 +504,8 @@ value_t MillGameAi_ab::alphaBetaPruning(depth_t depth, value_t alpha, value_t be
#ifdef BOOK_LEARNING
// 检索开局库
if (gameContext->stage == GAME_PLACING && findBookHash(hash, hashValue)) {
if (gameContext->turn == PLAYER2) {
if (positionContext->stage == GAME_PLACING && findBookHash(hash, hashValue)) {
if (positionContext->turn == PLAYER2) {
// 是否需对后手扣分 // TODO: 先后手都处理
node->value += 1;
}
@ -521,18 +521,18 @@ value_t MillGameAi_ab::alphaBetaPruning(depth_t depth, value_t alpha, value_t be
}
// 生成子节点树,即生成每个合理的着法
MoveList::generateLegalMoves(*this, gameTemp, node, rootNode, bestMove);
MoveList::generateLegalMoves(*this, dummyPosition, node, rootNode, bestMove);
// 根据演算模型执行 MiniMax 检索,对先手,搜索 Max, 对后手,搜索 Min
minMax = gameTemp.whosTurn() == PLAYER1 ? -INF_VALUE : INF_VALUE;
minMax = dummyPosition.whosTurn() == PLAYER1 ? -INF_VALUE : INF_VALUE;
for (auto child : node->children) {
// 上下文入栈保存,以便后续撤销着法
contextStack.push(gameTemp.context);
contextStack.push(dummyPosition.context);
// 执行着法
gameTemp.command(child->move);
dummyPosition.command(child->move);
#ifdef DEAL_WITH_HORIZON_EFFECT
// 克服“水平线效应”: 若遇到吃子,则搜索深度增加
@ -553,10 +553,10 @@ value_t MillGameAi_ab::alphaBetaPruning(depth_t depth, value_t alpha, value_t be
value = alphaBetaPruning(depth - 1 + epsilon, alpha, beta, child);
// 上下文弹出栈,撤销着法
gameTemp.context = contextStack.top();
dummyPosition.context = contextStack.top();
contextStack.pop();
if (gameTemp.whosTurn() == PLAYER1) {
if (dummyPosition.whosTurn() == PLAYER1) {
// 为走棋一方的层, 局面对走棋的一方来说是以 α 为评价
// 取最大值
@ -686,10 +686,10 @@ const char* MillGameAi_ab::bestMove()
// 检查是否必败
if (game_.getGiveUpIfMostLose() == true) {
if (position_.getGiveUpIfMostLose() == true) {
bool isMostLose = true; // 是否必败
Player whosTurn = game_.whosTurn();
Player whosTurn = position_.whosTurn();
for (auto child : rootNode->children) {
// TODO: 使用常量代替
@ -750,15 +750,15 @@ const char *MillGameAi_ab::move2string(move_t move)
int r, s;
if (move < 0) {
gameTemp.context.board.locationToPolar(-move, r, s);
dummyPosition.context.board.locationToPolar(-move, r, s);
sprintf(cmdline, "-(%1u,%1u)", r, s);
} else if (move & 0x7f00) {
int r1, s1;
gameTemp.context.board.locationToPolar(move >> 8, r1, s1);
gameTemp.context.board.locationToPolar(move & 0x00ff, r, s);
dummyPosition.context.board.locationToPolar(move >> 8, r1, s1);
dummyPosition.context.board.locationToPolar(move & 0x00ff, r, s);
sprintf(cmdline, "(%1u,%1u)->(%1u,%1u)", r1, s1, r, s);
} else {
gameTemp.context.board.locationToPolar(move & 0x007f, r, s);
dummyPosition.context.board.locationToPolar(move & 0x007f, r, s);
sprintf(cmdline, "(%1u,%1u)", r, s);
}

View File

@ -75,7 +75,7 @@ public:
bool isTimeout; // 是否遍历到此结点时因为超时而被迫退出
bool isLeaf; // 是否为叶子结点, 叶子结点是决胜局面
bool visited; // 是否在遍历时访问过
GameStage stage; // 摆棋阶段还是走棋阶段
PositionStage stage; // 摆棋阶段还是走棋阶段
Action action; // 动作状态
int nPiecesOnBoardDiff; // 场上棋子个数和对手的差值
int nPiecesInHandDiff; // 手中的棋子个数和对手的差值
@ -97,7 +97,7 @@ public:
MillGameAi_ab();
~MillGameAi_ab();
void setGame(const MillGame &game);
void setPosition(const Position &position);
void quit()
{
@ -185,15 +185,15 @@ protected:
private:
// 原始模型
MillGame game_;
Position position_;
// 演算用的模型
MillGame gameTemp;
Position dummyPosition;
GameContext *gameContext {};
PositionContext *positionContext {};
// hash 计算时,各种转换用的模型
MillGame gameTempShift;
Position dummyPositionShift;
// 根节点
Node *rootNode {nullptr};
@ -218,9 +218,9 @@ private:
// 局面数据栈
//#ifdef MEMORY_POOL
// StackAlloc<MillGame::GameContext, MemoryPool<MillGame::GameContext> > contextStack;
// StackAlloc<MillGame::PositionContext, MemoryPool<MillGame::PositionContext> > contextStack;
//#else
stack<GameContext> contextStack;
stack<PositionContext> contextStack;
//#endif
// 标识,用于跳出剪枝算法,立即返回

View File

@ -50,17 +50,17 @@ bool TranspositionTable::findHash(hash_t hash, TranspositionTable::HashValue &ha
return iter;
// 变换局面,查找 hash (废弃)
gameTempShift = gameTemp;
dummyPositionShift = dummyPosition;
for (int i = 0; i < 2; i++) {
if (i)
gameTempShift.mirror(false);
dummyPositionShift.mirror(false);
for (int j = 0; j < 2; j++) {
if (j)
gameTempShift.turn(false);
dummyPositionShift.turn(false);
for (int k = 0; k < 4; k++) {
gameTempShift.rotate(k * 90, false);
iter = hashmap.find(gameTempShift.getHash());
dummyPositionShift.rotate(k * 90, false);
iter = hashmap.find(dummyPositionShift.getHash());
if (iter != hashmap.end())
return iter;
}

View File

@ -26,7 +26,7 @@
AiThread::AiThread(int id, QObject *parent) :
QThread(parent),
waiting_(false),
game_(nullptr),
position_(nullptr),
aiDepth(2),
aiTime(3600)
{
@ -60,12 +60,12 @@ AiThread::~AiThread()
wait();
}
void AiThread::setAi(const MillGame &game)
void AiThread::setAi(const Position &position)
{
mutex.lock();
this->game_ = &game;
ai_ab.setGame(*(this->game_));
this->position_ = &position;
ai_ab.setPosition(*(this->position_));
#ifdef TRANSPOSITION_TABLE_ENABLE
// 新下一盘前清除哈希表 (注意可能同时存在每步之前清除)
@ -77,11 +77,11 @@ void AiThread::setAi(const MillGame &game)
mutex.unlock();
}
void AiThread::setAi(const MillGame &game, depth_t depth, int time)
void AiThread::setAi(const Position &position, depth_t depth, int time)
{
mutex.lock();
this->game_ = &game;
ai_ab.setGame(game);
this->position_ = &position;
ai_ab.setPosition(position);
aiDepth = depth;
aiTime = time;
mutex.unlock();
@ -107,7 +107,7 @@ void AiThread::run()
while (!isInterruptionRequested()) {
mutex.lock();
i = MillGame::playerToId(game_->whosTurn());
i = Position::playerToId(position_->whosTurn());
if (i != id || waiting_) {
pauseCondition.wait(&mutex);
@ -115,7 +115,7 @@ void AiThread::run()
continue;
}
ai_ab.setGame(*game_);
ai_ab.setPosition(*position_);
emit calcStarted();
mutex.unlock();

View File

@ -54,8 +54,8 @@ protected:
public:
// AI设置
void setAi(const MillGame &game);
void setAi(const MillGame &game, depth_t depth, int time);
void setAi(const Position &position);
void setAi(const Position &position, depth_t depth, int time);
Server *getServer()
{
@ -107,7 +107,7 @@ private:
QWaitCondition pauseCondition;
// 主线程棋对象的引用
const MillGame *game_;
const Position *position_;
// Alpha-Beta剪枝算法类
MillGameAi_ab ai_ab;

View File

@ -24,7 +24,7 @@
#include "search.h"
#include "movegen.h"
MillGame::MillGame()
Position::Position()
{
// 单独提出 board 等数据,免得每次都写 context.board;
board_ = context.board.locations;
@ -44,40 +44,40 @@ MillGame::MillGame()
score_1 = score_2 = score_draw = 0;
}
MillGame::~MillGame() = default;
Position::~Position() = default;
MillGame::MillGame(const MillGame &game)
Position::Position(const Position &position)
{
*this = game;
*this = position;
}
MillGame &MillGame::operator= (const MillGame &game)
Position &Position::operator= (const Position &position)
{
if (this == &game)
if (this == &position)
return *this;
currentRule = game.currentRule;
context = game.context;
currentStep = game.currentStep;
moveStep = game.moveStep;
randomMove_ = game.randomMove_;
giveUpIfMostLose_ = game.giveUpIfMostLose_;
currentRule = position.currentRule;
context = position.context;
currentStep = position.currentStep;
moveStep = position.moveStep;
randomMove_ = position.randomMove_;
giveUpIfMostLose_ = position.giveUpIfMostLose_;
board_ = context.board.locations;
currentLocation = game.currentLocation;
winner = game.winner;
startTime = game.startTime;
currentTime = game.currentTime;
elapsedSeconds_1 = game.elapsedSeconds_1;
elapsedSeconds_2 = game.elapsedSeconds_2;
move_ = game.move_;
memcpy(cmdline, game.cmdline, sizeof(cmdline));
cmdlist = game.cmdlist;
tips = game.tips;
currentLocation = position.currentLocation;
winner = position.winner;
startTime = position.startTime;
currentTime = position.currentTime;
elapsedSeconds_1 = position.elapsedSeconds_1;
elapsedSeconds_2 = position.elapsedSeconds_2;
move_ = position.move_;
memcpy(cmdline, position.cmdline, sizeof(cmdline));
cmdlist = position.cmdlist;
tips = position.tips;
return *this;
}
int MillGame::playerToId(enum Player player)
int Position::playerToId(enum Player player)
{
if (player == PLAYER1)
return 1;
@ -87,7 +87,7 @@ int MillGame::playerToId(enum Player player)
return 0;
}
Player MillGame::getOpponent(Player player)
Player Position::getOpponent(Player player)
{
switch (player)
{
@ -103,7 +103,7 @@ Player MillGame::getOpponent(Player player)
}
// 设置配置
bool MillGame::configure(bool giveUpIfMostLose, bool randomMove)
bool Position::configure(bool giveUpIfMostLose, bool randomMove)
{
// 设置是否必败时认输
this->giveUpIfMostLose_ = giveUpIfMostLose;
@ -115,7 +115,7 @@ bool MillGame::configure(bool giveUpIfMostLose, bool randomMove)
}
// 设置棋局状态和棋盘数据,用于初始化
bool MillGame::setContext(const struct Rule *rule, step_t maxStepsLedToDraw, int maxTimeLedToLose,
bool Position::setContext(const struct Rule *rule, step_t maxStepsLedToDraw, int maxTimeLedToLose,
step_t initialStep, int flags, const char *board,
int nPiecesInHand_1, int nPiecesInHand_2, int nPiecesNeedRemove)
{
@ -266,7 +266,7 @@ bool MillGame::setContext(const struct Rule *rule, step_t maxStepsLedToDraw, int
return false;
}
void MillGame::getContext(struct Rule &rule, step_t &step, int &flags,
void Position::getContext(struct Rule &rule, step_t &step, int &flags,
int *&board, int &nPiecesInHand_1, int &nPiecesInHand_2, int &nPiecesNeedRemove)
{
rule = this->currentRule;
@ -278,7 +278,7 @@ void MillGame::getContext(struct Rule &rule, step_t &step, int &flags,
nPiecesNeedRemove = context.nPiecesNeedRemove;
}
bool MillGame::reset()
bool Position::reset()
{
if (context.stage == GAME_NOTSTARTED &&
elapsedSeconds_1 == elapsedSeconds_2 == 0) {
@ -351,7 +351,7 @@ bool MillGame::reset()
return false;
}
bool MillGame::start()
bool Position::start()
{
switch (context.stage) {
// 如果游戏已经开始则返回false
@ -374,7 +374,7 @@ bool MillGame::start()
}
}
bool MillGame::place(int location, int time_p, int8_t rs)
bool Position::place(int location, int time_p, int8_t rs)
{
// 如果局面为“结局”返回false
if (context.stage == GAME_OVER)
@ -556,7 +556,7 @@ out:
return true;
}
bool MillGame::_place(int r, int s, int time_p)
bool Position::_place(int r, int s, int time_p)
{
// 转换为 location
int location = context.board.polarToLocation(r, s);
@ -564,7 +564,7 @@ bool MillGame::_place(int r, int s, int time_p)
return place(location, time_p, true);
}
bool MillGame::_capture(int r, int s, int time_p)
bool Position::_capture(int r, int s, int time_p)
{
// 转换为 location
int location = context.board.polarToLocation(r, s);
@ -572,7 +572,7 @@ bool MillGame::_capture(int r, int s, int time_p)
return capture(location, time_p, 1);
}
bool MillGame::capture(int location, int time_p, int8_t cp)
bool Position::capture(int location, int time_p, int8_t cp)
{
// 如果局面为"未开局"或“结局”返回false
if (context.stage == GAME_NOTSTARTED || context.stage == GAME_OVER)
@ -714,7 +714,7 @@ out:
return true;
}
bool MillGame::choose(int location)
bool Position::choose(int location)
{
// 如果局面不是"中局”返回false
if (context.stage != GAME_MOVING)
@ -745,12 +745,12 @@ bool MillGame::choose(int location)
return false;
}
bool MillGame::choose(int r, int s)
bool Position::choose(int r, int s)
{
return choose(context.board.polarToLocation(r, s));
}
bool MillGame::giveup(Player loser)
bool Position::giveup(Player loser)
{
if (context.stage == GAME_NOTSTARTED ||
context.stage == GAME_OVER ||
@ -778,7 +778,7 @@ bool MillGame::giveup(Player loser)
}
// 打算用个C++的命令行解析库的,简单的没必要,但中文编码有极小概率出问题
bool MillGame::command(const char *cmd)
bool Position::command(const char *cmd)
{
int r, t;
step_t s;
@ -863,7 +863,7 @@ bool MillGame::command(const char *cmd)
return false;
}
bool MillGame::command(int move)
bool Position::command(int move)
{
if (move < 0) {
return capture(-move);
@ -880,7 +880,7 @@ bool MillGame::command(int move)
return false;
}
inline int MillGame::update(int time_p /*= -1*/)
inline int Position::update(int time_p /*= -1*/)
{
int ret = -1;
time_t *player_ms = (context.turn == PLAYER1 ? &elapsedSeconds_1 : &elapsedSeconds_2);
@ -911,13 +911,13 @@ inline int MillGame::update(int time_p /*= -1*/)
}
// 是否分出胜负
bool MillGame::win()
bool Position::win()
{
return win(false);
}
// 是否分出胜负
bool MillGame::win(bool forceDraw)
bool Position::win(bool forceDraw)
{
if (context.stage == GAME_OVER) {
return true;
@ -1043,7 +1043,7 @@ bool MillGame::win(bool forceDraw)
}
// 计算玩家1和玩家2的棋子活动能力之差
int MillGame::getMobilityDiff(enum Player turn, const Rule &rule, int nPiecesOnBoard_1, int nPiecesOnBoard_2, bool includeFobidden)
int Position::getMobilityDiff(enum Player turn, const Rule &rule, int nPiecesOnBoard_1, int nPiecesOnBoard_2, bool includeFobidden)
{
int *board = context.board.locations;
int mobility1 = 0;
@ -1066,7 +1066,7 @@ int MillGame::getMobilityDiff(enum Player turn, const Rule &rule, int nPiecesOnB
return diff;
}
void MillGame::cleanForbiddenPoints()
void Position::cleanForbiddenPoints()
{
int location = 0;
@ -1082,7 +1082,7 @@ void MillGame::cleanForbiddenPoints()
}
}
enum Player MillGame::changeTurn()
enum Player Position::changeTurn()
{
// 设置轮到谁走
context.turn = (context.turn == PLAYER1) ? PLAYER2 : PLAYER1;
@ -1090,7 +1090,7 @@ enum Player MillGame::changeTurn()
return context.turn;
}
void MillGame::setTips()
void Position::setTips()
{
switch (context.stage) {
case GAME_NOTSTARTED:
@ -1156,7 +1156,7 @@ void MillGame::setTips()
}
}
void MillGame::getElapsedTime(time_t &p1_ms, time_t &p2_ms)
void Position::getElapsedTime(time_t &p1_ms, time_t &p2_ms)
{
update();
@ -1174,7 +1174,7 @@ void MillGame::getElapsedTime(time_t &p1_ms, time_t &p2_ms)
* 001
*/
void MillGame::constructHash()
void Position::constructHash()
{
context.hash = 0;
@ -1182,7 +1182,7 @@ void MillGame::constructHash()
memcpy(context.zobrist, zobrist0, sizeof(hash_t) * Board::N_LOCATIONS * POINT_TYPE_COUNT);
}
hash_t MillGame::getHash()
hash_t Position::getHash()
{
// TODO: 每次获取哈希值时更新 hash 值低8位放在此处调用不优雅
updateHashMisc();
@ -1190,7 +1190,7 @@ hash_t MillGame::getHash()
return context.hash;
}
hash_t MillGame::updateHash(int location)
hash_t Position::updateHash(int location)
{
// PieceType is board_[location]
@ -1203,12 +1203,12 @@ hash_t MillGame::updateHash(int location)
return context.hash;
}
hash_t MillGame::revertHash(int location)
hash_t Position::revertHash(int location)
{
return updateHash(location);
}
hash_t MillGame::updateHashMisc()
hash_t Position::updateHashMisc()
{
// 清除标记位
context.hash &= static_cast<hash_t>(~0xFF);
@ -1224,7 +1224,7 @@ hash_t MillGame::updateHashMisc()
}
context.hash |= static_cast<hash_t>(context.nPiecesNeedRemove) << 2;
context.hash |= static_cast<hash_t>(context.nPiecesInHand_1) << 4; // TODO: 或许换 game.stage 也可以?
context.hash |= static_cast<hash_t>(context.nPiecesInHand_1) << 4; // TODO: 或许换 position.stage 也可以?
return context.hash;
}

View File

@ -19,8 +19,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifndef MILLGAME_H
#define MILLGAME_H
#ifndef POSITION_H
#define POSITION_H
#include <string>
#include <cstring>
@ -36,7 +36,7 @@ using namespace std;
// 棋局结构体,算法相关,包含当前棋盘数据
// 单独分离出来供AI判断局面用生成置换表时使用
class GameContext
class PositionContext
{
public:
Board board;
@ -48,7 +48,7 @@ public:
hash_t zobrist[Board::N_LOCATIONS][POINT_TYPE_COUNT]{};
// 局面阶段标识
enum GameStage stage;
enum PositionStage stage;
// 轮流状态标识
enum Player turn;
@ -75,9 +75,9 @@ public:
};
// 棋类(在数据模型内,玩家只分先后手,不分黑白)
// 注意:MillGame类不是线程安全的!
// 所以不能跨线程修改MillGame类的静态成员变量,切记!
class MillGame
// 注意:Position 类不是线程安全的!
// 所以不能跨线程修改 Position 类的静态成员变量,切记!
class Position
{
// AI友元类
friend class MillGameAi_ab;
@ -111,14 +111,14 @@ private:
void constructHash();
public:
explicit MillGame();
virtual ~MillGame();
explicit Position();
virtual ~Position();
// 拷贝构造函数
explicit MillGame(const MillGame &);
explicit Position(const Position &);
// 运算符重载
MillGame &operator=(const MillGame &);
Position &operator=(const Position &);
// 设置配置
bool configure(bool giveUpIfMostLose, bool randomMove);
@ -188,7 +188,7 @@ public:
}
// 获取局面阶段标识
enum GameStage getStage() const
enum PositionStage getStage() const
{
return context.stage;
}
@ -328,7 +328,7 @@ public:
public: /* TODO: move to private */
// 棋局上下文
GameContext context;
PositionContext context;
// 当前使用的规则
struct Rule currentRule
@ -404,4 +404,4 @@ private:
string tips;
};
#endif /* MILLGAME_H */
#endif /* POSITION_H */

View File

@ -66,7 +66,7 @@ enum Player : uint8_t
};
// 局面阶段标识
enum GameStage : uint16_t
enum PositionStage : uint16_t
{
GAME_NONE = 0x0000,
GAME_NOTSTARTED = 0x0001, // 未开局

View File

@ -117,9 +117,9 @@ const QMap<int, QStringList> GameController::getActions()
void GameController::gameStart()
{
game_.configure(giveUpIfMostLose_, randomMove_);
game_.start();
gameTemp = game_;
position_.configure(giveUpIfMostLose_, randomMove_);
position_.start();
dummyPosition = position_;
// 每隔100毫秒调用一次定时器处理函数
if (timeID == 0) {
@ -137,15 +137,15 @@ void GameController::gameReset()
timeID = 0;
// 棋未下完,则算对手得分
if (game_.getStage() == GAME_MOVING &&
game_.whoWin() == PLAYER_NOBODY) {
if (position_.getStage() == GAME_MOVING &&
position_.whoWin() == PLAYER_NOBODY) {
giveUp();
}
// 重置游戏
game_.configure(giveUpIfMostLose_, randomMove_);
game_.reset();
gameTemp = game_;
position_.configure(giveUpIfMostLose_, randomMove_);
position_.reset();
dummyPosition = position_;
// 停掉线程
if (!isAutoRestart) {
@ -161,7 +161,7 @@ void GameController::gameReset()
currentPiece = nullptr;
// 重新绘制棋盘
scene.setDiagonal(game_.getRule()->hasObliqueLines);
scene.setDiagonal(position_.getRule()->hasObliqueLines);
// 绘制所有棋子,放在起始位置
// 0: 先手第1子 1后手第1子
@ -170,7 +170,7 @@ void GameController::gameReset()
PieceItem::Models md;
PieceItem *newP;
for (int i = 0; i < game_.getRule()->nTotalPiecesEachSide; i++) {
for (int i = 0; i < position_.getRule()->nTotalPiecesEachSide; i++) {
// 先手的棋子
md = isInverted ? PieceItem::whitePiece : PieceItem::blackPiece;
newP = new PieceItem;
@ -179,7 +179,7 @@ void GameController::gameReset()
newP->setNum(i + 1);
// 如果重复三连不可用,则显示棋子序号,九连棋专用玩法
if (!(game_.getRule()->allowRemovePiecesRepeatedly))
if (!(position_.getRule()->allowRemovePiecesRepeatedly))
newP->setShowNum(true);
pieceList.append(newP);
@ -193,7 +193,7 @@ void GameController::gameReset()
newP->setNum(i + 1);
// 如果重复三连不可用,则显示棋子序号,九连棋专用玩法
if (!(game_.getRule()->allowRemovePiecesRepeatedly))
if (!(position_.getRule()->allowRemovePiecesRepeatedly))
newP->setShowNum(true);
pieceList.append(newP);
@ -201,7 +201,7 @@ void GameController::gameReset()
}
// 读取规则限时要求
timeLimit = game_.getRule()->maxTimeLedToLose;
timeLimit = position_.getRule()->maxTimeLedToLose;
// 如果规则不要求计时则time1和time2表示已用时间
if (timeLimit <= 0) {
@ -215,7 +215,7 @@ void GameController::gameReset()
// 更新棋谱
manualListModel.removeRows(0, manualListModel.rowCount());
manualListModel.insertRow(0);
manualListModel.setData(manualListModel.index(0), game_.getCmdLine());
manualListModel.setData(manualListModel.index(0), position_.getCmdLine());
currentRow = 0;
// 发出信号通知主窗口更新LCD显示
@ -224,13 +224,13 @@ void GameController::gameReset()
emit time2Changed(qtime.toString("hh:mm:ss"));
// 发信号更新状态栏
message = QString::fromStdString(game_.getTips());
message = QString::fromStdString(position_.getTips());
emit statusBarChanged(message);
// 更新比分 LCD 显示
emit score1Changed(QString::number(game_.score_1, 10));
emit score2Changed(QString::number(game_.score_2, 10));
emit scoreDrawChanged(QString::number(game_.score_draw, 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));
// 播放音效
//playSound(":/sound/resources/sound/newgame.wav");
@ -275,8 +275,8 @@ void GameController::setRule(int ruleNo, step_t stepLimited /*= -1*/, int timeLi
}
// 设置模型规则,重置游戏
game_.setContext(&RULES[ruleNo], stepsLimit, timeLimit);
gameTemp = game_;
position_.setContext(&RULES[ruleNo], stepsLimit, timeLimit);
dummyPosition = position_;
// 重置游戏
gameReset();
@ -284,11 +284,11 @@ void GameController::setRule(int ruleNo, step_t stepLimited /*= -1*/, int timeLi
void GameController::setEngine1(bool arg)
{
game_.configure(giveUpIfMostLose_, randomMove_);
position_.configure(giveUpIfMostLose_, randomMove_);
isAiPlayer1 = arg;
if (arg) {
ai1.setAi(game_);
ai1.setAi(position_);
if (ai1.isRunning())
ai1.resume();
else
@ -300,11 +300,11 @@ void GameController::setEngine1(bool arg)
void GameController::setEngine2(bool arg)
{
game_.configure(giveUpIfMostLose_, randomMove_);
position_.configure(giveUpIfMostLose_, randomMove_);
isAiPlayer2 = arg;
if (arg) {
ai2.setAi(game_);
ai2.setAi(position_);
if (ai2.isRunning())
ai2.resume();
else
@ -325,8 +325,8 @@ void GameController::setAiDepthTime(depth_t depth1, int time1, depth_t depth2, i
ai2.wait();
}
ai1.setAi(game_, depth1, time1);
ai2.setAi(game_, depth2, time2);
ai1.setAi(position_, depth1, time1);
ai2.setAi(position_, depth2, time2);
if (isAiPlayer1) {
ai1.start();
@ -398,13 +398,13 @@ void GameController::flip()
ai2.wait();
}
game_.context.board.mirror(game_.cmdlist, game_.cmdline, game_.move_, game_.currentRule, game_.currentLocation);
game_.context.board.rotate(180, game_.cmdlist, game_.cmdline, game_.move_, game_.currentRule, game_.currentLocation);
gameTemp = game_;
position_.context.board.mirror(position_.cmdlist, position_.cmdline, position_.move_, position_.currentRule, position_.currentLocation);
position_.context.board.rotate(180, position_.cmdlist, position_.cmdline, position_.move_, position_.currentRule, position_.currentLocation);
dummyPosition = position_;
// 更新棋谱
int row = 0;
for (const auto &str : *(game_.getCmdList())) {
for (const auto &str : *(position_.getCmdList())) {
manualListModel.setData(manualListModel.index(row++), str.c_str());
}
@ -414,8 +414,8 @@ void GameController::flip()
else
stageChange(currentRow, true);
ai1.setAi(game_);
ai2.setAi(game_);
ai1.setAi(position_);
ai2.setAi(position_);
if (isAiPlayer1) {
ai1.start();
@ -438,13 +438,13 @@ void GameController::mirror()
ai2.wait();
}
game_.context.board.mirror(game_.cmdlist, game_.cmdline, game_.move_, game_.currentRule, game_.currentLocation);
gameTemp = game_;
position_.context.board.mirror(position_.cmdlist, position_.cmdline, position_.move_, position_.currentRule, position_.currentLocation);
dummyPosition = position_;
// 更新棋谱
int row = 0;
for (const auto &str : *(game_.getCmdList())) {
for (const auto &str : *(position_.getCmdList())) {
manualListModel.setData(manualListModel.index(row++), str.c_str());
}
@ -456,8 +456,8 @@ void GameController::mirror()
else
stageChange(currentRow, true);
ai1.setAi(game_);
ai2.setAi(game_);
ai1.setAi(position_);
ai2.setAi(position_);
if (isAiPlayer1) {
ai1.start();
@ -480,13 +480,13 @@ void GameController::turnRight()
ai2.wait();
}
game_.context.board.rotate(-90, game_.cmdlist, game_.cmdline, game_.move_, game_.currentRule, game_.currentLocation);
gameTemp = game_;
position_.context.board.rotate(-90, position_.cmdlist, position_.cmdline, position_.move_, position_.currentRule, position_.currentLocation);
dummyPosition = position_;
// 更新棋谱
int row = 0;
for (const auto &str : *(game_.getCmdList())) {
for (const auto &str : *(position_.getCmdList())) {
manualListModel.setData(manualListModel.index(row++), str.c_str());
}
@ -496,8 +496,8 @@ void GameController::turnRight()
else
stageChange(currentRow, true);
ai1.setAi(game_);
ai2.setAi(game_);
ai1.setAi(position_);
ai2.setAi(position_);
if (isAiPlayer1) {
ai1.start();
@ -520,20 +520,20 @@ void GameController::turnLeft()
ai2.wait();
}
game_.context.board.rotate(90, game_.cmdlist, game_.cmdline, game_.move_, game_.currentRule, game_.currentLocation);
gameTemp = game_;
position_.context.board.rotate(90, position_.cmdlist, position_.cmdline, position_.move_, position_.currentRule, position_.currentLocation);
dummyPosition = position_;
// 更新棋谱
int row = 0;
for (const auto &str : *(game_.getCmdList())) {
for (const auto &str : *(position_.getCmdList())) {
manualListModel.setData(manualListModel.index(row++), str.c_str());
}
// 刷新显示
updateScence();
ai1.setAi(game_);
ai2.setAi(game_);
ai1.setAi(position_);
ai2.setAi(position_);
if (isAiPlayer1) {
ai1.start();
}
@ -548,7 +548,7 @@ void GameController::timerEvent(QTimerEvent *event)
static QTime qt1, qt2;
// 玩家的已用时间
game_.getElapsedTime(remainingTime1, remainingTime2);
position_.getElapsedTime(remainingTime1, remainingTime2);
// 如果规则要求计时则time1和time2表示倒计时
if (timeLimit > 0) {
@ -564,7 +564,7 @@ void GameController::timerEvent(QTimerEvent *event)
emit time2Changed(qt2.toString("hh:mm:ss"));
// 如果胜负已分
if (game_.whoWin() != PLAYER_NOBODY) {
if (position_.whoWin() != PLAYER_NOBODY) {
// 停止计时
killTimer(timeID);
@ -572,7 +572,7 @@ void GameController::timerEvent(QTimerEvent *event)
timeID = 0;
// 发信号更新状态栏
message = QString::fromStdString(game_.getTips());
message = QString::fromStdString(position_.getTips());
emit statusBarChanged(message);
// 弹框
@ -609,8 +609,8 @@ void GameController::timerEvent(QTimerEvent *event)
bool GameController::isAIsTurn()
{
return ((game_.whosTurn() == PLAYER1 && isAiPlayer1) ||
(game_.whosTurn() == PLAYER2 && isAiPlayer2));
return ((position_.whosTurn() == PLAYER1 && isAiPlayer1) ||
(position_.whosTurn() == PLAYER2 && isAiPlayer2));
}
// 关键槽函数根据QGraphicsScene的信号和状态来执行选子、落子或去子
@ -643,17 +643,17 @@ bool GameController::actionPiece(QPointF pos)
if (QMessageBox::Ok == msgBox.exec()) {
#endif /* !MOBILE_APP_UI */
game_ = gameTemp;
position_ = dummyPosition;
manualListModel.removeRows(currentRow + 1, manualListModel.rowCount() - currentRow - 1);
// 如果再决出胜负后悔棋,则重新启动计时
if (game_.whoWin() == PLAYER_NOBODY) {
if (position_.whoWin() == PLAYER_NOBODY) {
// 重新启动计时
timeID = startTimer(100);
// 发信号更新状态栏
message = QString::fromStdString(game_.getTips());
message = QString::fromStdString(position_.getTips());
emit statusBarChanged(message);
#ifndef MOBILE_APP_UI
}
@ -664,7 +664,7 @@ bool GameController::actionPiece(QPointF pos)
}
// 如果未开局则开局
if (game_.getStage() == GAME_NOTSTARTED)
if (position_.getStage() == GAME_NOTSTARTED)
gameStart();
// 判断执行选子、落子或去子
@ -672,10 +672,10 @@ bool GameController::actionPiece(QPointF pos)
PieceItem *piece = nullptr;
QGraphicsItem *item = scene.itemAt(pos, QTransform());
switch (game_.getAction()) {
switch (position_.getAction()) {
case ACTION_PLACE:
if (game_._place(r, s)) {
if (game_.getAction() == ACTION_CAPTURE) {
if (position_._place(r, s)) {
if (position_.getAction() == ACTION_CAPTURE) {
// 播放成三音效
playSound(":/sound/resources/sound/capture.wav");
} else {
@ -693,7 +693,7 @@ bool GameController::actionPiece(QPointF pos)
piece = qgraphicsitem_cast<PieceItem *>(item);
if (!piece)
break;
if (game_.choose(r, s)) {
if (position_.choose(r, s)) {
// 播放选子音效
playSound(":/sound/resources/sound/choose.wav");
result = true;
@ -704,7 +704,7 @@ bool GameController::actionPiece(QPointF pos)
break;
case ACTION_CAPTURE:
if (game_._capture(r, s)) {
if (position_._capture(r, s)) {
// 播放音效
playSound(":/sound/resources/sound/remove.wav");
result = true;
@ -721,7 +721,7 @@ bool GameController::actionPiece(QPointF pos)
if (result) {
// 发信号更新状态栏
message = QString::fromStdString(game_.getTips());
message = QString::fromStdString(position_.getTips());
emit statusBarChanged(message);
// 将新增的棋谱行插入到ListModel
@ -729,7 +729,7 @@ bool GameController::actionPiece(QPointF pos)
int k = 0;
// 输出命令行
for (const auto & i : *(game_.getCmdList())) {
for (const auto & i : *(position_.getCmdList())) {
// 跳过已添加的因标准list容器没有下标
if (k++ <= currentRow)
continue;
@ -739,16 +739,16 @@ bool GameController::actionPiece(QPointF pos)
// 播放胜利或失败音效
#ifndef DONOT_PLAY_WIN_SOUND
if (game_.whoWin() != PLAYER_NOBODY &&
if (position_.whoWin() != PLAYER_NOBODY &&
(manualListModel.data(manualListModel.index(currentRow - 1))).toString().contains("Time over."))
playSound(":/sound/resources/sound/win.wav");
#endif
// AI设置
if (&game_ == &(this->game_)) {
if (&position_ == &(this->position_)) {
// 如果还未决出胜负
if (game_.whoWin() == PLAYER_NOBODY) {
if (game_.whosTurn() == PLAYER1) {
if (position_.whoWin() == PLAYER_NOBODY) {
if (position_.whosTurn() == PLAYER1) {
if (isAiPlayer1) {
ai1.resume();
}
@ -768,7 +768,7 @@ bool GameController::actionPiece(QPointF pos)
ai2.stop();
// 弹框
//message = QString::fromStdString(game_.getTips());
//message = QString::fromStdString(position_.getTips());
//QMessageBox::about(NULL, "游戏结果", message);
}
}
@ -782,11 +782,11 @@ bool GameController::giveUp()
{
bool result = false;
if (game_.whosTurn() == PLAYER1) {
result = game_.giveup(PLAYER1);
if (position_.whosTurn() == PLAYER1) {
result = position_.giveup(PLAYER1);
}
else if (game_.whosTurn() == PLAYER2) {
result = game_.giveup(PLAYER2);
else if (position_.whosTurn() == PLAYER2) {
result = position_.giveup(PLAYER2);
}
if (result) {
@ -795,14 +795,14 @@ bool GameController::giveUp()
int k = 0;
// 输出命令行
for (const auto & i : *(game_.getCmdList())) {
for (const auto & i : *(position_.getCmdList())) {
// 跳过已添加的因标准list容器没有下标
if (k++ <= currentRow)
continue;
manualListModel.insertRow(++currentRow);
manualListModel.setData(manualListModel.index(currentRow), i.c_str());
}
if (game_.whoWin() != PLAYER_NOBODY)
if (position_.whoWin() != PLAYER_NOBODY)
playSound(":/sound/resources/sound/loss.wav");
}
@ -824,7 +824,7 @@ bool GameController::command(const QString &cmd, bool update /* = true */)
// 声音
QString sound;
switch (game_.getAction()) {
switch (position_.getAction()) {
case ACTION_CHOOSE:
case ACTION_PLACE:
sound = ":/sound/resources/sound/drog.wav";
@ -837,44 +837,44 @@ bool GameController::command(const QString &cmd, bool update /* = true */)
}
// 如果未开局则开局
if (game_.getStage() == GAME_NOTSTARTED) {
if (position_.getStage() == GAME_NOTSTARTED) {
gameStart();
}
if (!game_.command(cmd.toStdString().c_str()))
if (!position_.command(cmd.toStdString().c_str()))
return false;
if (sound == ":/sound/resources/sound/drog.wav" && game_.getAction() == ACTION_CAPTURE) {
if (sound == ":/sound/resources/sound/drog.wav" && position_.getAction() == ACTION_CAPTURE) {
sound = ":/sound/resources/sound/capture.wav";
}
if (update) {
playSound(sound);
updateScence(game_);
updateScence(position_);
}
// 发信号更新状态栏
message = QString::fromStdString(game_.getTips());
message = QString::fromStdString(position_.getTips());
emit statusBarChanged(message);
// 对于新开局
if (game_.getCmdList()->size() <= 1) {
if (position_.getCmdList()->size() <= 1) {
manualListModel.removeRows(0, manualListModel.rowCount());
manualListModel.insertRow(0);
manualListModel.setData(manualListModel.index(0), game_.getCmdLine());
manualListModel.setData(manualListModel.index(0), position_.getCmdLine());
currentRow = 0;
}
// 对于当前局
else {
currentRow = manualListModel.rowCount() - 1;
// 跳过已添加行,迭代器不支持+运算符,只能一个个++
auto i = (game_.getCmdList()->begin());
for (int r = 0; i != (game_.getCmdList())->end(); i++) {
auto i = (position_.getCmdList()->begin());
for (int r = 0; i != (position_.getCmdList())->end(); i++) {
if (r++ > currentRow)
break;
}
// 将新增的棋谱行插入到ListModel
while (i != game_.getCmdList()->end()) {
while (i != position_.getCmdList()->end()) {
manualListModel.insertRow(++currentRow);
manualListModel.setData(manualListModel.index(currentRow), (*i++).c_str());
}
@ -882,17 +882,17 @@ bool GameController::command(const QString &cmd, bool update /* = true */)
// 播放胜利或失败音效
#ifndef DONOT_PLAY_WIN_SOUND
if (game_.whoWin() != PLAYER_NOBODY &&
if (position_.whoWin() != PLAYER_NOBODY &&
(manualListModel.data(manualListModel.index(currentRow - 1))).toString().contains("Time over.")) {
playSound(":/sound/resources/sound/win.wav");
}
#endif
// AI设置
if (&game_ == &(this->game_)) {
if (&position_ == &(this->position_)) {
// 如果还未决出胜负
if (game_.whoWin() == PLAYER_NOBODY) {
if (game_.whosTurn() == PLAYER1) {
if (position_.whoWin() == PLAYER_NOBODY) {
if (position_.whosTurn() == PLAYER1) {
if (isAiPlayer1) {
ai1.resume();
}
@ -925,7 +925,7 @@ bool GameController::command(const QString &cmd, bool update /* = true */)
#ifdef MESSAGEBOX_ENABLE
// 弹框
message = QString::fromStdString(game_.getTips());
message = QString::fromStdString(position_.getTips());
QMessageBox::about(NULL, "游戏结果", message);
#endif
}
@ -958,24 +958,24 @@ bool GameController::stageChange(int row, bool forceUpdate)
for (int i = 0; i <= row; i++) {
loggerDebug("%s\n", mlist.at(i).toStdString().c_str());
gameTemp.command(mlist.at(i).toStdString().c_str());
dummyPosition.command(mlist.at(i).toStdString().c_str());
}
// 下面这步关键,会让悔棋者承担时间损失
gameTemp.setStartTime(game_.getStartTimeb());
dummyPosition.setStartTime(position_.getStartTimeb());
// 刷新棋局场景
updateScence(gameTemp);
updateScence(dummyPosition);
return true;
}
bool GameController::updateScence()
{
return updateScence(game_);
return updateScence(position_);
}
bool GameController::updateScence(MillGame &game)
bool GameController::updateScence(Position &game)
{
const int *board = game.getBoard();
QPointF pos;

View File

@ -192,7 +192,7 @@ public slots:
// 更新棋局显示,每步后执行才能刷新局面
bool updateScence();
bool updateScence(MillGame &game);
bool updateScence(Position &game);
// 显示网络配置窗口
void showNetworkWindow();
@ -204,10 +204,10 @@ protected:
private:
// 棋对象的数据模型
MillGame game_;
Position position_;
// 棋对象的数据模型(临时)
MillGame gameTemp;
Position dummyPosition;
// 2个AI的线程
AiThread ai1, ai2;