我已经在Google和Stackoverflow上搜索了这个问题,但我仍然不明白minimax函数是如何工作的。
我发现维基百科条目有函数的伪代码版本:
function integer minimax(node, depth)
if node is a terminal node or depth <= 0:
return the heuristic value of node
α = -∞
for child in node: # evaluation is identical for both players
α = max(α, -minimax(child, depth-1))
return α
我在Google上发现的其他几个minimax函数基本上都是一样的;我正在尝试用C ++实现这个,这是我到目前为止所提出的:
double miniMax(Board eval, int iterations)
{
//I evaluate the board from both players' point of view and subtract the difference
if(iterations == 0)
return boardEval(eval, playerNumber) - boardEval(eval, opponentSide());
/*Here, playerTurn tells the findPossibleMoves function whose turn it is;
I mean, how do you generate a list of possible moves if you don't even know
whose turn it's supposed to be? But the problem is, I don't see where I can
get playerTurn from, as there are only 2 parameters in all the examples of
minimax I've seen*/
vector<int> moves = eval.findPossibleMoves(playerTurn);
//I'm assuming -∞ in the wikipedia article means a very low number?
int result = -999999999;
//Now I run this loop to evaluate each possible move
/*Also, the Lua example in the wiki article has
alpha = node.player==1 and math.max(alpha,score) or math.min(alpha,score)
Is alpha a boolean there?!*/
for(int i = 0; i * 2 < moves.size(); i++)
{
//I make a copy of the board...
Board temp = eval;
/*and make the next possible move... once again playerTurn crops up, and I
don't know where I can get that variable from*/
temp.putPiece(moves[i * 2], moves[i * 2 + 1], playerTurn);
/*So do I create a function max that returns the bigger of two doubles?*/
result = max(result, -miniMax(temp, iterations - 1));
}
return result;
/*So now I've returned the maximum score from all possible moves within a certain
# of moves; so how do I know which move to make? I have the score; how do I know
which sequence of moves that score belongs to?*/
}
正如你所看到的,我对这个极小极大功能感到很困惑。请至少给我一些提示来帮助我。
谢谢! :)
答案 0 :(得分:2)
来自维基百科的样本正在使用Alpha / Beta修剪进行NegaMax 。
直接命名可能会对你有所帮助:
基础是MiniMax,文字实现将涉及2个轮流(相互递归)的方法,每边1个。
懒惰的程序员将其转换为NegaMax,这是一种策略性放置-
运算符的方法。
Alpha / Beta修剪跟踪最佳移动窗口(多个深度)以检测死枝。
您的playerTurn
用于确定轮到谁。在NegaMax中,您可以从奇数或偶数的深度(迭代)得出这个。但是使用2个参数(myColor,otherColor)会更容易,并在每个级别切换它们。
答案 1 :(得分:1)
你的miniMax()函数应该记住它到目前为止发现的最佳动作。所以代替这段代码:
/*So do I create a function max that returns the bigger of two doubles?*/
result = max(result, -miniMax(temp, iterations - 1));
你应该这样做:
/*So do I create a function max that returns the bigger of two doubles?*/
double score = -miniMax(temp, iterations - 1);
if (score > result)
{
result = score;
bestMove = i;
}
当然,您需要一个变量“bestMove”以及一种将最佳移动返回给调用者的方法。
答案 2 :(得分:1)
将playerTurn
变量作为参数添加到miniMax
,并调用当前玩家最初和递归移动的miniMax
。
此外,opponentSide
必须是playerTurn
的函数。
答案 3 :(得分:1)
从游戏树搜索开始的好地方是chess programming wiki。关于此举的问题:我认为最常见的是有两个最大功能。两个最大函数之间的区别在于,一个仅返回分数,另一个返回分数和最佳移动。递归调用顺序如下:
maxWithBestMoveReturn(...) --> min(...) --> max(...) --> min(...)
有一些关于Alpha Beta算法的伪代码的好文章:
评论中的问题:和math.max(alpha,score)或math.min(alpha,score)alpha是布尔值吗?!
没有alpha是alpha beta算法中绑定的窗口。 alpha值将使用新值更新。因为alpha和beta与negamax-Function的递归调用交换,alpha变量指的是下一个递归调用中的beta变量。
对playerTurn变量的一个注意事项:minimax或alpha-beta算法不需要此信息。所以我会将信息 - 谁是下一个 - 提供给董事会结构。函数findPossibleMoves和boardEval从Board-Structure获取所需的所有信息。
递归中断条件的一个注释:如果我理解你的代码是正确的,那么你只有iterations == o
的代码。我认为这意味着算法已达到所需的深度。但是,如果算法没有可能的移动,那么算法达到了这个深度。也许你应该写下面的内容:
vector<int> moves = findPossibleMoves(...);
if (!moves.size())
return boardEval(...);
答案 4 :(得分:0)
在您的伪代码中,节点变量必须包含有关当前电路板位置(或其他)的所有信息。这些信息将包括轮到谁移动。