使用AlphaBeta修剪来提高此MiniMax的性能
Improving Performance of this MiniMax with AlphaBeta Pruning
我为一个奥赛罗(可逆)游戏实现了以下alpha-beta极大极小值。我已经从这个线程中修复了一些问题。这次我想提高这个功能的性能。MAX_DEPTH=8需要很长时间。可以做些什么来加快性能,同时保持人工智能的体面?
mm_out minimax(Grid& G, int alpha, int beta, Action& A, uint pn, uint depth, bool stage) {
if (G.check_terminal_state() || depth == MAX_DEPTH) {
return mm_out(A, G.get_utility(pn));
}
// add end game score total here
set<Action> succ_temp = G.get_successors(pn);
for (Action a : succ_temp) {
Grid gt(G);
a.evaluate(gt);
}
set<Action, action_greater> successors(succ_temp.begin(), succ_temp.end());
// if no successor, that player passes
if (successors.size()) {
for (auto a = successors.begin(); a != successors.end(); ++a) {
Grid gt(G);
gt.do_move(pn, a->get_x(), a->get_y(), !PRINT_ERR);
Action at = *a;
mm_out mt = minimax(gt, alpha, beta, at, pn ^ 1, depth + 1, !stage);
int temp = mt.val;
// A = mt.best_move;
if (stage == MINIMAX_MAX) {
if (alpha < temp) {
alpha = temp;
A = *a;
}
if (alpha >= beta) {
return mm_out(A, beta);
}
}
else {
if (beta > temp) {
beta = temp;
A = *a;
}
if (alpha >= beta) {
return mm_out(A, alpha);
}
}
}
return mm_out(A, (stage == MINIMAX_MAX) ? alpha : beta);
}
else {
return mm_out(A, (stage == MINIMAX_MAX) ? (std::numeric_limits<int>::max() - 1) : (std::numeric_limits<int>::min() + 1));
}
}
实用功能:
int Grid::get_utility(uint pnum) const {
if (pnum)
return wcount - bcount;
return bcount - wcount;
}
有几种方法可以加快搜索功能的性能。如果正确地实现这些技术,在修剪许多节点时,它们对算法的准确性几乎不会造成损害。
- 您可以实现的第一种技术是换位表。换位表将游戏搜索树中所有先前访问过的节点存储在哈希表中。大多数游戏状态,尤其是在深度搜索中,可以通过各种换位或在同一最终状态中复活的移动顺序来达到。通过存储以前搜索过的游戏状态,如果找到已经搜索过的状态,可以使用表中存储的数据,并停止在该节点深化搜索。将游戏状态存储在哈希表中的标准技术称为Zobrist哈希。关于实施换位表的详细信息可在网上查阅
-
你的程序应该包括的第二件事是移动排序。这本质上意味着,不是按照你生成动作的顺序来检查动作,而是按照最有可能产生阿尔法-贝塔截止值的顺序(即先检查好动作)。显然,你不知道哪一个动作是最好的,但大多数动作都可以用一种天真的技巧来安排。例如,在《奥赛罗》中,应该首先检查位于角落或边缘的动作。命令移动应该会导致更多的截断和搜索速度的提高。这对准确性造成零损失。
-
您也可以添加打开的书本。通常开局需要最长的搜索时间,因为棋盘上充满了更多的可能性。开场白是一个数据库,它存储了在前几个回合中可以做出的每一个可能的动作,以及对它的最佳反应。在《奥赛罗》中,由于分支因子较低,这将在开场白中特别有用
- Probecut。我不打算在这里详述,因为这是一种更先进的技术。然而,它与奥塞洛有很好的结果,所以我想我会发布这个链接。https://chessprogramming.wikispaces.com/ProbCut
相关文章:
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- OpenMP阵列性能较差
- 递归列出所有目录中的C++与Python与Ruby的性能
- 大小相等但成员数量不同的结构之间的性能差异
- 为什么constexpr的性能比正常表达式差
- 在类中使用随机生成器时出现性能问题
- 在main()之外初始化std::vector会导致性能下降(多线程)
- 海湾合作委员会 ARM 性能下降
- GCC 和 Clang 代码性能的巨大差异
- 在容量内调整矢量大小时的性能影响
- 了解算法的性能差异(如果以不同的编程语言实现)
- 未达到的情况会影响开关外壳性能
- QStringList vs list<shared_ptr<QString>> 性能比较C++
- 是否总是可以将使用递归编写的程序重写为不使用递归的程序C++,性能观点是什么?
- 哪种方法更好,性能明智
- C++ 特征库:引用的性能开销<>
- 与多个 for 循环与单个 for 循环 wrt 相关的性能从多映射获取数据
- 基于范围的 for 循环range_declaration中各种说明符之间的性能差异
- std::p mr::memory_resource 如何与 std::container 产生性能差异?
- 使用AlphaBeta修剪来提高此MiniMax的性能