增加 AI 随机走子的选项
去除 MOVE_PRIORITY_TABLE_SUPPORT 宏, 固定走这个宏的逻辑, 至于是否打乱着法则视 randomMove 而定.
This commit is contained in:
parent
d8f9f375ab
commit
07e1c12f3a
|
@ -292,6 +292,7 @@
|
|||
<addaction name="actionAnimation_A"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionAutoRestart_A"/>
|
||||
<addaction name="actionRandomMove_R"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menu_H">
|
||||
<property name="title">
|
||||
|
@ -1101,6 +1102,17 @@
|
|||
<string>自动重新开局(&A)</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionRandomMove_R">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>电脑着法随机(&R)</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<customwidgets>
|
||||
|
|
|
@ -81,8 +81,6 @@
|
|||
|
||||
//#define DONOT_DELETE_TREE
|
||||
|
||||
#define MOVE_PRIORITY_TABLE_SUPPORT
|
||||
|
||||
#define SORT_CONSIDER_PRUNED
|
||||
|
||||
//#define MESSAGEBOX_ENABLE
|
||||
|
|
|
@ -200,21 +200,21 @@ struct MillGameAi_ab::Node *MillGameAi_ab::addNode(
|
|||
return newNode;
|
||||
}
|
||||
|
||||
#ifdef MOVE_PRIORITY_TABLE_SUPPORT
|
||||
#ifdef RANDOM_MOVE
|
||||
void MillGameAi_ab::shuffleMovePriorityTable()
|
||||
{
|
||||
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 = { 8, 10, 12, 14, 24, 26, 28, 30 }; // 内外圈十字架
|
||||
array<int, 8> movePriorityTable3 = { 24, 26, 28, 30, 8, 10, 12, 14 }; // 外内圈十字架
|
||||
|
||||
uint32_t seed = static_cast<uint32_t>(std::chrono::system_clock::now().time_since_epoch().count());
|
||||
if (chess_.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));
|
||||
std::shuffle(movePriorityTable1.begin(), movePriorityTable1.end(), std::default_random_engine(seed));
|
||||
std::shuffle(movePriorityTable2.begin(), movePriorityTable2.end(), std::default_random_engine(seed));
|
||||
std::shuffle(movePriorityTable3.begin(), movePriorityTable3.end(), std::default_random_engine(seed));
|
||||
std::shuffle(movePriorityTable0.begin(), movePriorityTable0.end(), std::default_random_engine(seed));
|
||||
std::shuffle(movePriorityTable1.begin(), movePriorityTable1.end(), std::default_random_engine(seed));
|
||||
std::shuffle(movePriorityTable2.begin(), movePriorityTable2.end(), std::default_random_engine(seed));
|
||||
std::shuffle(movePriorityTable3.begin(), movePriorityTable3.end(), std::default_random_engine(seed));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
movePriorityTable[i + 0] = movePriorityTable0[i];
|
||||
|
@ -232,8 +232,6 @@ void MillGameAi_ab::shuffleMovePriorityTable()
|
|||
movePriorityTable[i + 16] = movePriorityTable3[i];
|
||||
}
|
||||
}
|
||||
#endif // #ifdef RANDOM_MOVE
|
||||
#endif // MOVE_PRIORITY_TABLE_SUPPORT
|
||||
|
||||
void MillGameAi_ab::generateLegalMoves(Node *node, move_t bestMove)
|
||||
{
|
||||
|
@ -273,27 +271,6 @@ void MillGameAi_ab::generateLegalMoves(Node *node, move_t bestMove)
|
|||
|
||||
node->children.reserve(newCapacity + 2 /* TODO: 未细调故再多留余量2 */);
|
||||
|
||||
#ifdef MOVE_PRIORITY_TABLE_SUPPORT
|
||||
#ifdef RANDOM_MOVE
|
||||
|
||||
#else // RANDOM_MOVE
|
||||
int movePriorityTable[MOVE_PRIORITY_TABLE_SIZE] = {
|
||||
17, 19, 21, 23, // 星位
|
||||
25, 27, 29, 31, // 外圈四个顶点
|
||||
9, 11, 13, 15, // 内圈四个顶点
|
||||
16, 18, 20, 22, // 中圈十字架
|
||||
24, 26, 28, 30, // 外圈十字架
|
||||
8, 10, 12, 14, // 中圈十字架
|
||||
};
|
||||
#endif // RANDOM_MOVE
|
||||
#else // MOVE_PRIORITY_TABLE_SUPPORT
|
||||
int movePriorityTable[MOVE_PRIORITY_TABLE_SIZE] = {
|
||||
8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23,
|
||||
24, 25, 26, 27, 28, 29, 30, 31,
|
||||
};
|
||||
#endif // MOVE_PRIORITY_TABLE_SUPPORT
|
||||
|
||||
// 如果有子节点,则返回,避免重复建立
|
||||
if (!node->children.empty()) {
|
||||
return;
|
||||
|
@ -331,12 +308,9 @@ void MillGameAi_ab::generateLegalMoves(Node *node, move_t bestMove)
|
|||
// 对于移子阶段
|
||||
if (chessTemp.context.stage & MillGame::GAME_MOVING) {
|
||||
int newPos, oldPos;
|
||||
#ifdef MOVE_PRIORITY_TABLE_SUPPORT
|
||||
|
||||
// 尽量走理论上较差的位置的棋子
|
||||
for (int i = MOVE_PRIORITY_TABLE_SIZE - 1; i >= 0; i--) {
|
||||
#else
|
||||
for (int i = 0; i < MOVE_PRIORITY_TABLE_SIZE; i++) {
|
||||
#endif // MOVE_PRIORITY_TABLE_SUPPORT
|
||||
oldPos = movePriorityTable[i];
|
||||
|
||||
if (!chessTemp.choose(oldPos)) {
|
||||
|
@ -752,11 +726,8 @@ int MillGameAi_ab::alphaBetaPruning(depth_t depth)
|
|||
}
|
||||
#endif // THREEFOLD_REPETITION
|
||||
|
||||
#ifdef MOVE_PRIORITY_TABLE_SUPPORT
|
||||
#ifdef RANDOM_MOVE
|
||||
shuffleMovePriorityTable();
|
||||
#endif // RANDOM_MOVE
|
||||
#endif // MOVE_PRIORITY_TABLE_SUPPORT
|
||||
// 随机打乱着法顺序
|
||||
shuffleMovePriorityTable();
|
||||
|
||||
#ifdef IDS_SUPPORT
|
||||
// 深化迭代
|
||||
|
|
|
@ -211,11 +211,7 @@ protected:
|
|||
depth_t changeDepth(depth_t originalDepth);
|
||||
|
||||
// 随机打乱着法搜索顺序
|
||||
#ifdef MOVE_PRIORITY_TABLE_SUPPORT
|
||||
#ifdef RANDOM_MOVE
|
||||
void shuffleMovePriorityTable();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HASH_MAP_ENABLE
|
||||
// 查找哈希表
|
||||
|
@ -269,9 +265,12 @@ private:
|
|||
// 标识,用于跳出剪枝算法,立即返回
|
||||
bool requiredQuit {false};
|
||||
|
||||
#ifdef MOVE_PRIORITY_TABLE_SUPPORT
|
||||
array<int, MillGame::N_RINGS *MillGame::N_SEATS> movePriorityTable {};
|
||||
#endif // MOVE_PRIORITY_TABLE_SUPPORT
|
||||
// 着法顺序表, 后续会被打乱
|
||||
array<int, MillGame::N_RINGS *MillGame::N_SEATS> movePriorityTable {
|
||||
8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23,
|
||||
24, 25, 26, 27, 28, 29, 30, 31,
|
||||
};
|
||||
|
||||
// 定义极大值
|
||||
static const value_t INF_VALUE = 0x1 << 14;
|
||||
|
|
|
@ -168,6 +168,7 @@ MillGame &MillGame::operator = (const MillGame &chess)
|
|||
context = chess.context;
|
||||
currentStep = chess.currentStep;
|
||||
moveStep = chess.moveStep;
|
||||
randomMove_ = chess.randomMove_;
|
||||
board_ = context.board;
|
||||
currentPos = chess.currentPos;
|
||||
winner = chess.winner;
|
||||
|
@ -211,7 +212,7 @@ MillGame::Player MillGame::getOpponent(MillGame::Player player)
|
|||
void MillGame::createMoveTable()
|
||||
{
|
||||
#ifdef CONST_MOVE_TABLE
|
||||
#ifdef MOVE_PRIORITY_TABLE_SUPPORT
|
||||
#if 1
|
||||
const int moveTable_obliqueLine[MillGame::N_POINTS][MillGame::N_MOVE_DIRECTIONS] = {
|
||||
/* 0 */ {0, 0, 0, 0},
|
||||
/* 1 */ {0, 0, 0, 0},
|
||||
|
@ -399,7 +400,7 @@ void MillGame::createMoveTable()
|
|||
/* 38 */ {0, 0, 0, 0},
|
||||
/* 39 */ {0, 0, 0, 0},
|
||||
};
|
||||
#endif /* MOVE_PRIORITY_TABLE_SUPPORT */
|
||||
#endif
|
||||
|
||||
if (currentRule.hasObliqueLines) {
|
||||
memcpy(moveTable, moveTable_obliqueLine, sizeof(moveTable));
|
||||
|
@ -662,10 +663,19 @@ void MillGame::createMillTable()
|
|||
#endif
|
||||
}
|
||||
|
||||
// 设置配置
|
||||
bool MillGame::configure(bool randomMove)
|
||||
{
|
||||
// 设置是否随机走子
|
||||
this->randomMove_ = randomMove;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 设置棋局状态和棋盘数据,用于初始化
|
||||
bool MillGame::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)
|
||||
step_t initialStep, int flags, const char *board,
|
||||
int nPiecesInHand_1, int nPiecesInHand_2, int nPiecesNeedRemove)
|
||||
{
|
||||
// 有效性判断
|
||||
if (maxTimeLedToLose < 0) {
|
||||
|
|
|
@ -303,6 +303,9 @@ public:
|
|||
// 运算符重载
|
||||
MillGame &operator=(const MillGame &);
|
||||
|
||||
// 设置配置
|
||||
bool configure(bool randomMove);
|
||||
|
||||
// 设置棋局状态和棋盘上下文,用于初始化
|
||||
bool setContext(const struct Rule *rule,
|
||||
step_t maxStepsLedToDraw = 0, // 限制步数
|
||||
|
@ -361,6 +364,12 @@ public:
|
|||
return moveStep;
|
||||
}
|
||||
|
||||
// 获取 AI 是否随机走子
|
||||
bool getRandomMove() const
|
||||
{
|
||||
return randomMove_;
|
||||
}
|
||||
|
||||
// 获取局面阶段标识
|
||||
enum GameStage getStage() const
|
||||
{
|
||||
|
@ -567,6 +576,9 @@ private:
|
|||
// 从走子阶段开始或上次吃子起的步数
|
||||
int moveStep {};
|
||||
|
||||
// AI 是否随机走子
|
||||
bool randomMove_ {true};
|
||||
|
||||
// 游戏起始时间
|
||||
time_t startTime {};
|
||||
|
||||
|
|
|
@ -54,7 +54,8 @@ GameController::GameController(GameScene & scene, QObject * parent) :
|
|||
timeID(0),
|
||||
ruleNo_(-1),
|
||||
timeLimit(0),
|
||||
stepsLimit(50)
|
||||
stepsLimit(50),
|
||||
randomMove_(true)
|
||||
{
|
||||
// 已在view的样式表中添加背景,scene中不用添加背景
|
||||
// 区别在于,view中的背景不随视图变换而变换,scene中的背景随视图变换而变换
|
||||
|
@ -116,6 +117,7 @@ const QMap<int, QStringList> GameController::getActions()
|
|||
|
||||
void GameController::gameStart()
|
||||
{
|
||||
chess_.configure(randomMove_);
|
||||
chess_.start();
|
||||
chessTemp = chess_;
|
||||
|
||||
|
@ -141,6 +143,7 @@ void GameController::gameReset()
|
|||
}
|
||||
|
||||
// 重置游戏
|
||||
chess_.configure(randomMove_);
|
||||
chess_.reset();
|
||||
chessTemp = chess_;
|
||||
|
||||
|
@ -281,6 +284,8 @@ void GameController::setRule(int ruleNo, MillGame::step_t stepLimited /*= -1*/,
|
|||
|
||||
void GameController::setEngine1(bool arg)
|
||||
{
|
||||
chess_.configure(randomMove_);
|
||||
|
||||
isAiPlayer1 = arg;
|
||||
if (arg) {
|
||||
ai1.setAi(chess_);
|
||||
|
@ -295,6 +300,8 @@ void GameController::setEngine1(bool arg)
|
|||
|
||||
void GameController::setEngine2(bool arg)
|
||||
{
|
||||
chess_.configure(randomMove_);
|
||||
|
||||
isAiPlayer2 = arg;
|
||||
if (arg) {
|
||||
ai2.setAi(chess_);
|
||||
|
@ -369,6 +376,11 @@ void GameController::setAutoRestart(bool arg)
|
|||
isAutoRestart = arg;
|
||||
}
|
||||
|
||||
void GameController::setRandomMove(bool arg)
|
||||
{
|
||||
randomMove_ = arg;
|
||||
}
|
||||
|
||||
// 上下翻转
|
||||
void GameController::flip()
|
||||
{
|
||||
|
|
|
@ -70,6 +70,11 @@ public:
|
|||
return stepsLimit;
|
||||
}
|
||||
|
||||
bool getRandomMove()
|
||||
{
|
||||
return randomMove_;
|
||||
}
|
||||
|
||||
bool isAnimation()
|
||||
{
|
||||
return hasAnimation;
|
||||
|
@ -148,6 +153,9 @@ public slots:
|
|||
// 是否自动开局
|
||||
void setAutoRestart(bool arg = false);
|
||||
|
||||
// AI 是否随机走子
|
||||
void setRandomMove(bool arg);
|
||||
|
||||
// 上下翻转
|
||||
void flip();
|
||||
|
||||
|
@ -235,6 +243,9 @@ private:
|
|||
// 是否棋局结束后自动重新开局
|
||||
bool isAutoRestart;
|
||||
|
||||
// AI 是否随机走子
|
||||
bool randomMove_;
|
||||
|
||||
// 定时器ID
|
||||
int timeID;
|
||||
|
||||
|
|
|
@ -209,6 +209,9 @@ void MillGameWindow::initialize()
|
|||
connect(ui.actionAutoRestart_A, SIGNAL(toggled(bool)),
|
||||
game, SLOT(setAutoRestart(bool)));
|
||||
|
||||
connect(ui.actionRandomMove_R, SIGNAL(toggled(bool)),
|
||||
game, SLOT(setRandomMove(bool)));
|
||||
|
||||
// 视图上下翻转
|
||||
connect(ui.actionFlip_F, &QAction::triggered,
|
||||
game, &GameController::flip);
|
||||
|
|
Loading…
Reference in New Issue