招法改名为着法并添加更多注释
This commit is contained in:
parent
2366f8eae1
commit
22d450a193
|
@ -85,7 +85,7 @@
|
|||
</widget>
|
||||
<widget class="QMenu" name="menu_M">
|
||||
<property name="title">
|
||||
<string>招法(&M)</string>
|
||||
<string>着法(&M)</string>
|
||||
</property>
|
||||
<addaction name="actionBegin_S"/>
|
||||
<addaction name="actionPrevious_B"/>
|
||||
|
|
|
@ -17,7 +17,7 @@ public:
|
|||
~AiThread();
|
||||
|
||||
signals:
|
||||
// 招法信号
|
||||
// 着法信号
|
||||
void command(const QString &cmdline, bool update = true);
|
||||
|
||||
// 开始计算的信号
|
||||
|
|
|
@ -44,7 +44,7 @@ GameController::GameController(GameScene & scene, QObject * parent) :
|
|||
|
||||
gameReset();
|
||||
|
||||
// 关联AI和控制器的招法命令行
|
||||
// 关联AI和控制器的着法命令行
|
||||
connect(&ai1, SIGNAL(command(const QString &, bool)),
|
||||
this, SLOT(command(const QString &, bool)));
|
||||
connect(&ai2, SIGNAL(command(const QString &, bool)),
|
||||
|
|
|
@ -111,7 +111,7 @@ const int NineChess::onBoard[(N_RINGS + 2) * N_SEATS] = {
|
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
// 招法表
|
||||
// 着法表
|
||||
int NineChess::moveTable[(N_RINGS + 2) * N_SEATS][N_MOVE_DIRECTIONS] = { 0 };
|
||||
|
||||
// 成三表
|
||||
|
@ -398,7 +398,7 @@ bool NineChess::setContext(const struct Rule *rule, int maxStepsLedToDraw, int m
|
|||
// 胜负标识
|
||||
winner = NOBODY;
|
||||
|
||||
// 生成招法表
|
||||
// 生成着法表
|
||||
createMoveTable();
|
||||
|
||||
// 生成成三表
|
||||
|
@ -713,7 +713,7 @@ bool NineChess::place(int c, int p, long time_p /* = -1*/)
|
|||
break;
|
||||
}
|
||||
|
||||
// 不在招法表中
|
||||
// 不在着法表中
|
||||
if (i == 4)
|
||||
return false;
|
||||
}
|
||||
|
@ -1027,7 +1027,7 @@ bool NineChess::place(int pos)
|
|||
if (pos == moveTable[currentPos][i])
|
||||
break;
|
||||
}
|
||||
// 不在招法表中
|
||||
// 不在着法表中
|
||||
if (i == 4)
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -205,7 +205,7 @@ private:
|
|||
// 空棋盘点位,用于判断一个棋子位置是否在棋盘上
|
||||
static const int onBoard[(N_RINGS + 2) * N_SEATS];
|
||||
|
||||
// 招法表,每个位置有最多4种走法:顺时针、逆时针、向内、向外
|
||||
// 着法表,每个位置有最多4种走法:顺时针、逆时针、向内、向外
|
||||
// 这个表跟规则有关,一旦规则改变需要重新修改
|
||||
static int moveTable[(N_RINGS + 2) * N_SEATS][N_MOVE_DIRECTIONS];
|
||||
|
||||
|
@ -213,7 +213,7 @@ private:
|
|||
// 这个表跟规则有关,一旦规则改变需要重新修改
|
||||
static int millTable[(N_RINGS + 2) * N_SEATS][3][2];
|
||||
|
||||
// 生成招法表
|
||||
// 生成着法表
|
||||
void createMoveTable();
|
||||
|
||||
// 生成成三表
|
||||
|
@ -317,7 +317,7 @@ public:
|
|||
// 获取位置点棋子的归属人
|
||||
enum Player getWhosPiece(int c, int p);
|
||||
|
||||
// 获取当前招法
|
||||
// 获取当前着法
|
||||
const char *getCmdLine() const
|
||||
{
|
||||
return cmdline;
|
||||
|
@ -481,7 +481,7 @@ private:
|
|||
// 玩家2用时(毫秒)
|
||||
long elapsedMS_2;
|
||||
|
||||
/* 当前招法,AI会用到,如下表示
|
||||
/* 当前着法,AI会用到,如下表示
|
||||
0x 00 00
|
||||
pos1 pos2
|
||||
开局落子:0x00??,??为棋盘上的位置
|
||||
|
@ -503,8 +503,8 @@ private:
|
|||
*/
|
||||
int32_t move_;
|
||||
|
||||
// 招法命令行用于棋谱的显示和解析
|
||||
// 当前招法的命令行指令,即一招棋谱
|
||||
// 着法命令行用于棋谱的显示和解析
|
||||
// 当前着法的命令行指令,即一招棋谱
|
||||
char cmdline[32];
|
||||
|
||||
// 棋谱
|
||||
|
|
|
@ -137,9 +137,9 @@ void NineChessAi_ab::buildChildren(Node *node)
|
|||
(chessTemp.context.nPiecesOnBoard_1 > chessTemp.currentRule.nPiecesAtLeast || !chessTemp.currentRule.allowFlyWhenRemainThreePieces)) ||
|
||||
(chessTemp.context.turn == NineChess::PLAYER2 &&
|
||||
(chessTemp.context.nPiecesOnBoard_2 > chessTemp.currentRule.nPiecesAtLeast || !chessTemp.currentRule.allowFlyWhenRemainThreePieces))) {
|
||||
// 对于棋盘上还有3个子以上,或不允许飞子的情况,要求必须在招法表中
|
||||
// 对于棋盘上还有3个子以上,或不允许飞子的情况,要求必须在着法表中
|
||||
for (int moveDirection = NineChess::MOVE_DIRECTION_CLOCKWISE; moveDirection <= NineChess::MOVE_DIRECTION_OUTWARD; moveDirection++) {
|
||||
// 对于原有位置,遍历四个方向的招法,如果棋盘上为空位就加到结点列表中
|
||||
// 对于原有位置,遍历四个方向的着法,如果棋盘上为空位就加到结点列表中
|
||||
newPos = chessTemp.moveTable[oldPos][moveDirection];
|
||||
if (newPos && !chessTemp.board_[newPos]) {
|
||||
int move = (oldPos << 8) + newPos;
|
||||
|
@ -147,7 +147,7 @@ void NineChessAi_ab::buildChildren(Node *node)
|
|||
}
|
||||
}
|
||||
} else {
|
||||
// 对于棋盘上还有不到3个字,但允许飞子的情况,不要求在招法表中,是空位就行
|
||||
// 对于棋盘上还有不到3个字,但允许飞子的情况,不要求在着法表中,是空位就行
|
||||
for (newPos = NineChess::POS_BEGIN; newPos < NineChess::POS_END; newPos++) {
|
||||
if (!chessTemp.board_[newPos]) {
|
||||
int move = (oldPos << 8) + newPos;
|
||||
|
@ -488,7 +488,7 @@ int NineChessAi_ab::alphaBetaPruning(int depth)
|
|||
qDebug() << "IDS Time: " << time1.elapsed() / 1000.0 << "s";
|
||||
#endif /* IDS_SUPPORT */
|
||||
|
||||
value = alphaBetaPruning(d, -INF_VALUE, INF_VALUE, rootNode);
|
||||
value = alphaBetaPruning(d, -INF_VALUE /* alpha */, INF_VALUE /* beta */, rootNode);
|
||||
|
||||
qDebug() << "Total Time: " << time1.elapsed() / 1000.0 << "s\n";
|
||||
|
||||
|
@ -582,7 +582,7 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
|
|||
hashMapMutex.unlock();
|
||||
#endif /* HASH_MAP_ENABLE */
|
||||
|
||||
// 生成子节点树
|
||||
// 生成子节点树,即生成每个合理的着法
|
||||
buildChildren(node);
|
||||
|
||||
// 排序子节点树
|
||||
|
@ -593,10 +593,10 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
|
|||
minMax = chessTemp.whosTurn() == NineChess::PLAYER1 ? -INF_VALUE : INF_VALUE;
|
||||
|
||||
for (auto child : node->children) {
|
||||
// 上下文入栈保存
|
||||
// 上下文入栈保存,以便后续撤销着法
|
||||
contextStack.push(chessTemp.context);
|
||||
|
||||
// 替换为演算用的招法
|
||||
// 执行着法
|
||||
chessTemp.command(child->move);
|
||||
|
||||
#ifdef DEAL_WITH_HORIZON_EFFECT
|
||||
|
@ -611,31 +611,37 @@ int NineChessAi_ab::alphaBetaPruning(int depth, int alpha, int beta, Node *node)
|
|||
// 递归 Alpha-Beta 剪枝
|
||||
value = alphaBetaPruning(depth - 1 + epsilon, alpha, beta, child);
|
||||
|
||||
// 上下文弹出栈
|
||||
// 上下文弹出栈,撤销着法
|
||||
chessTemp.context = contextStack.top();
|
||||
contextStack.pop();
|
||||
|
||||
if (chessTemp.whosTurn() == NineChess::PLAYER1) {
|
||||
// 为走棋一方的层
|
||||
// 为走棋一方的层, 局面对走棋的一方来说是以 α 为评价
|
||||
|
||||
// 取最大值
|
||||
minMax = std::max(value, minMax);
|
||||
|
||||
// alpha 为走棋一方搜索到的最好值,任何比它小的值对当前结点的走棋方都没有意义
|
||||
// α 为走棋一方搜索到的最好值,任何比它小的值对当前结点的走棋方都没有意义
|
||||
// 如果某个着法的结果小于或等于 α,那么它就是很差的着法,因此可以抛弃
|
||||
alpha = std::max(value, alpha);
|
||||
} else {
|
||||
// 为走棋方的对手一方的层
|
||||
// 为走棋方的对手一方的层, 局面对对手一方来说是以 β 为评价
|
||||
|
||||
// 取最小值
|
||||
minMax = std::min(value, minMax);
|
||||
|
||||
// beta 表示对手目前的劣势,这是对手所能承受的最坏结果
|
||||
// beta 值越大,表示对手劣势越明显
|
||||
// 如果当前结点返回 beta 或比 beta 更好的值,作为父结点的对方就绝对不会选择这种策略
|
||||
// β 表示对手目前的劣势,这是对手所能承受的最坏结果
|
||||
// β 值越大,表示对手劣势越明显
|
||||
// 在对手看来,他总是会找到一个对策不比 β 更坏的
|
||||
// 如果当前结点返回 β 或比 β 更好的值,作为父结点的对方就绝对不会选择这种策略,
|
||||
// 如果搜索过程中返回 β 或比 β 更好的值,那就够好的了,走棋的一方就没有机会使用这种策略了。
|
||||
// 如果某个着法的结果大于或等于 β,那么整个结点就作废了,因为对手不希望走到这个局面,而它有别的着法可以避免到达这个局面。
|
||||
// 因此如果我们找到的评价大于或等于β,就证明了这个结点是不会发生的,因此剩下的合理着法没有必要再搜索。
|
||||
beta = std::min(value, beta);
|
||||
}
|
||||
|
||||
// 剪枝返回
|
||||
// 如果某个着法的结果大于 α 但小于β,那么这个着法就是走棋一方可以考虑走的
|
||||
// 否则剪枝返回
|
||||
if (alpha >= beta)
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ public:
|
|||
// 定义一个节点结构体
|
||||
struct Node
|
||||
{
|
||||
int move; // 招法的命令行指令,图上标示为节点前的连线
|
||||
int move; // 着法的命令行指令,图上标示为节点前的连线
|
||||
int value; // 节点的值
|
||||
list<struct Node*> children; // 子节点列表
|
||||
struct Node* parent; // 父节点
|
||||
|
@ -107,7 +107,7 @@ protected:
|
|||
// Alpha-Beta剪枝算法
|
||||
int alphaBetaPruning(int depth, int alpha, int beta, Node *node);
|
||||
|
||||
// 返回招法的命令行
|
||||
// 返回着法的命令行
|
||||
const char *move2string(int move);
|
||||
|
||||
// 篡改深度
|
||||
|
|
|
@ -251,7 +251,7 @@ void NineChessWindow::initialize()
|
|||
connect(ui.actionEnd_E, &QAction::triggered,
|
||||
this, &NineChessWindow::on_actionRowChange);
|
||||
|
||||
// 手动在listView里选择招法后更新的槽
|
||||
// 手动在listView里选择着法后更新的槽
|
||||
connect(ui.listView, &ManualListView::currentChangedSignal,
|
||||
this, &NineChessWindow::on_actionRowChange);
|
||||
|
||||
|
|
Loading…
Reference in New Issue