招法改名为着法并添加更多注释

This commit is contained in:
CalciteM Team 2019-07-06 15:32:19 +08:00
parent 2366f8eae1
commit 22d450a193
8 changed files with 37 additions and 31 deletions

View File

@ -85,7 +85,7 @@
</widget>
<widget class="QMenu" name="menu_M">
<property name="title">
<string>法(&amp;M)</string>
<string>法(&amp;M)</string>
</property>
<addaction name="actionBegin_S"/>
<addaction name="actionPrevious_B"/>

View File

@ -17,7 +17,7 @@ public:
~AiThread();
signals:
// 法信号
// 法信号
void command(const QString &cmdline, bool update = true);
// 开始计算的信号

View File

@ -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)),

View File

@ -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;
}

View File

@ -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];
// 棋谱

View File

@ -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;
}

View File

@ -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);
// 篡改深度

View File

@ -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);