我在为象棋游戏制作一个人工智能。
到目前为止,我已经成功实现了Alpha-Beta剪枝Minimax算法,它看起来是这样的(来自维基百科):
(* Initial call *)
alphabeta(origin, depth, -∞, +∞, TRUE)
function alphabeta(node, depth, α, β, maximizingPlayer)
if depth = 0 or node is a terminal node
return the heuristic value of node
if maximizingPlayer
for each child of node
α := max(α, alphabeta(child, depth - 1, α, β, FALSE))
if β ≤ α
break (* β cut-off *)
return α
else
for each child of node
β := min(β, alphabeta(child, depth - 1, α, β, TRUE))
if β ≤ α
break (* α cut-off *)
return β
由于这花费了太多的时间复杂性(逐一遍历所有的树),我遇到了一种叫做“历史启发式”的东西。
原始论文中的算法:
int AlphaBeta(pos, d, alpha, beta)
{
if (d=0 || game is over)
return Eval (pos); // evaluate leaf position from current player’s standpoint
score = - INFINITY; // preset return value
moves = Generate(pos); // generate successor moves
for i=1 to sizeof(moves) do // rating all moves
rating[i] = HistoryTable[ moves[i] ];
Sort( moves, rating ); // sorting moves according to their history scores
for i =1 to sizeof(moves) do { // look over all moves
Make(moves[i]); // execute current move
cur = - AlphaBeta(pos, d-1, -beta, -alpha); //call other player
if (cur > score) {
score = cur;
bestMove = moves[i]; // update best move if necessary
}
if (score > alpha) alpha = score; //adjust the search window
Undo(moves[i]); // retract current move
if (alpha >= beta) goto done; // cut off
}
done:
// update history score
HistoryTable[bestMove] = HistoryTable[bestMove] + Weight(d);
return score;
}
所以基本上,这个想法是跟踪一个散列表或者一个字典来记录以前的“移动”。
现在我很困惑这个“移动”在这里意味着什么。我不确定它是字面上指的单一移动还是每次移动后的整体状态。
例如,在国际象棋中,这个哈希表的“键”应该是什么?
> < li>
个人移动,如(女王到位置(0,1))或(骑士到位置(5,5))?
还是棋盘在个人移动后的整体状态?
如果是 1 的情况,我想在将“移动”记录到我的历史记录表中时没有考虑其他部分的位置?
从我的经验来看,与其他技术相比,历史启发式产生的好处可以忽略不计,对于一个基本的搜索程序来说是不值得的。这与使用转置表不是一回事。如果你想实现后者,我仍然建议不要这样做。有许多其他的技术可以用少得多的努力产生好的结果。事实上,高效正确的转置表是象棋引擎中最难编码的部分之一。
首先尝试修剪和移动排序启发式方法,其中大部分是一到几行代码。我在这篇文章中详细介绍了这些技术,它还给出了您可以期望的性能提升的估计值。
您可以使用换位表,这样可以避免多次评估同一块电路板。换位意味着您可以通过以不同的顺序移动来达到相同的棋盘状态。天真的例子:
1. e4 e5 2. Nf3 Nc6
1. e4 Nc6 2. Nf3 e5
这些戏剧的结果是相同的位置,但到达的位置不同。
http://en.wikipedia.org/wiki/Transposition_table
一种常见的方法称为Zobrist散列来散列国际象棋位置:
http://en.wikipedia.org/wiki/Zobrist_hashing
我认为在线的原始论文(the History Heuristic and Alpha Beta Search Enhancements in Practice,Jonathan Schaeffer)清楚地回答了这个问题。在论文中,作者将移动定义为棋盘上的2个索引(从正方形到),使用64x64表格(实际上,我认为他使用了位移位和单个索引数组)来包含移动历史。
作者比较了所有可用的移动排序方法,确定hh是最好的。如果当前的最佳实践已经建立了一种改进的移动排序形式(超越hh换位表),我也想知道它是什么。
抱歉,这是我的笔记。 在最后一天,我一直在阅读极大极小树和阿尔法数据修剪,为我的项目做准备。这是c语言中奥赛罗的实现。 我阅读了大量关于它的资料,我知道它被问了很多。在我开始我的评估功能之前,我想充分了解这一点。 在随附的图像中,我无法弄清楚函数和究竟会做什么,任何输入将不胜感激。 如果任何人有任何提示或事情,我应该注意在实现这个和我的奥赛罗评估功能,我愿意采取任何帮助,我可以找到。
我正在为游戏开发AI,我想使用MinMax算法和Alpha-Beta修剪。 我对它的工作原理有一个粗略的想法,但我仍然无法从头开始编写代码,所以我花了最近两天的时间在网上寻找某种伪代码。 我的问题是,我在网上找到的每个伪代码似乎都是基于找到最佳移动的值,而我需要返回最佳移动本身而不是数字。 我现在的代码是基于这个伪代码(源代码) 如您所见,这段代码返回一个数字,我想这是使一切正常工作所必需的(因为
我想为一个类似跳棋的游戏实现一个人工智能 我写了以下方法: -方法 这将返回所有按重量排序的有效移动的列表,其中重量是根据移动的类型和位置计算的 -方法 将移动应用于棋盘,如果有棋子被杀则返回1 -方法 以恢复板的先前状态。 这是一个零和游戏,所以人工智能应该最大化玩家颜色的棋子,最小化对手的棋子。 为此,最好的方法似乎是使用最小-最大和α-β修剪。这有以下伪码 但我还没有明白如何适应我的问题。有
我有一个存储时间跨度数据的表。该表的架构类似于: 我试图计算出每个记录id的开始和结束日期,即最小开始日期和最大结束日期。StartDate不可为null,所以我不需要担心这个问题,但我需要MAX(EndDate)来表示这是当前正在运行的时间跨度。 重要的是,我要保持EndDate的NULL值,并将其视为最大值。 最简单的尝试(如下)无法突出MIN和MAX将忽略NULLS的问题(来源:http:/
我已经为游戏跳棋编写了一个带有alpha-beta修剪的minimax算法,现在我正尝试使用negamax方法重写它。我希望这两者是等价的,因为negamax只是一种编写minimax的技术。但由于某种原因,我的两种算法表现不同。当我在相同的输入上运行它们时,negamax版本似乎评估了更多的状态,所以我认为alpha-beta修剪一定有问题。 下面的代码显示了这两种算法(
我有一个包含一些价格值的数据帧。不,我想有一个或最好的情况下有两个数据框,每篇文章的最大值和最小值没有 0 个值。 我用DT这样做(对于maxValue,一切都很完美): 但minValue Df显示0值。我也尝试过: 但是在这里我不知道如何使用 在最好的情况下,我希望每个产品的最大值和最小值都有dfs。