C++极小极大函数

发布于 2024-09-16 18:07:03 字数 2280 浏览 7 评论 0原文

我已经在 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?*/
}

如您所见,我对这个极小极大函数感到非常困惑。请至少给我一些提示来帮助我解决这个问题。

谢谢! :)

I have searched Google and Stackoverflow for this question, but I still don't understand how a minimax function works.

I found the wikipedia entry has a pseudocode version of the function:

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 α

Several other minimax functions I found with Google are basically the same thing; I'm trying to implement this in C++, and this is what I have come up with so far:

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?*/
}

As you can see, I'm pretty confused about this minimax function. Please at the very least give me some hints to help me with this.

Thanks! :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

瀟灑尐姊 2024-09-23 18:07:03

来自维基百科的示例正在执行 NegaMax 和 Alpha/Beta 修剪

直接命名可能会对您有所帮助:

  • 基础是 MiniMax,字面上的实现将涉及 2 个轮流(相互递归)的方法,每侧 1 个。

  • 懒惰的程序员将其转变为 NegaMax,这是一种策略性放置 - 运算符的方法。

  • Alpha/Beta 修剪正在跟踪最佳移动窗口(多个深度)以检测死分支。

您的 playerTurn 用于确定轮到谁了。在 NegaMax 中,您可以从深度(迭代)为奇数或偶数得出这一点。但使用 2 个参数(myColor、otherColor)并在每个级别切换它们会更容易。

That sample from Wikipedia is doing NegaMax with Alpha/Beta pruning.

You may be helped by getting the naming straight:

  • The basis is MiniMax, a literal implementation would involve 2 methods that take turns (mutually recursive), 1 for each side.

  • Lazy programmers turn this into NegaMax, one method with a strategically placed - operator.

  • Alpha/Beta pruning is keeping track of a Window of best moves (over multiple depths) to detect dead branches.

Your playerTurn is used to determine whose turn it is . In NegaMax you can derive this from the depth (iterations) being odd or even. But it would be easier to use 2 parameters (myColor, otherColor) and switch them at each level.

红颜悴 2024-09-23 18:07:03

你的 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”以及一种将找到的最佳移动返回给调用者的方法。

Your miniMax() function should remember the best move it found so far. So instead of this code:


  /*So do I create a function max that returns the bigger of two doubles?*/
  result = max(result, -miniMax(temp, iterations - 1));

You should do something like this:


  /*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;
  }

Of course, you need a variable "bestMove" and a way to return the best move found to the caller.

上课铃就是安魂曲 2024-09-23 18:07:03

playerTurn 变量添加为 miniMax 的参数,并递归调用当前玩家最初移动的 miniMax

此外,opponentSide 需要是 playerTurn 的函数。

Add the playerTurn variable as an argument to miniMax, and call miniMax which the current player's move initially and recursively.

Also, opponentSide needs to be a function of playerTurn.

梦中楼上月下 2024-09-23 18:07:03

国际象棋编程 wiki 是开始博弈树搜索的好地方。对于您关于此举的问题:我认为最常见的是有两个最大功能。两个 max 函数之间的区别在于,一个仅返回分数,另一个返回分数和最佳移动。递归调用顺序如下所示:

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 变量的一点注释:极小极大或α-β 算法不需要此信息。因此,我会将信息(下一个是谁)提供给董事会结构。函数 findPossibleMoves 和 boardEval 从 Board-Structure 获取所需的所有信息。

关于递归中断条件的一个注释:如果我正确理解你的代码,那么你只有带有 iterations == o 的代码。我认为这意味着算法已经达到了期望的深度。但是,如果在算法达到这个深度之前没有可能的移动,该怎么办?也许你应该写以下内容:

vector<int> moves = findPossibleMoves(...);
if (!moves.size())
    return boardEval(...);

A good place to start with game tree searching is the chess programming wiki. For your question about the move: I think it is most common to have two max-functions. The difference between the two max functions is that one returns only the score and the other returns the score and the best move. A recursive call order would be like following:

maxWithBestMoveReturn(...) --> min(...) --> max(...) --> min(...)

There are some good papers with pseudocode for the Alpha Beta algorithm:

To your question in the comment: and math.max(alpha,score) or math.min(alpha,score) Is alpha a boolean there?!

No alpha is a window bound in a alpha beta algorithm. The alpha value gets updated with a new value. Because alpha and beta are swapped with the recursive call of the negamax-Function the alpha variable refers to the beta variable in the next recursive call.

One note to the playerTurn variable: The minimax or alpha-beta algorithm doesn't need this information. So i would give the information -- who's next --, into the Board-Structure. The functions findPossibleMoves and boardEval get all information they need from the Board-Structure.

One note to the recursive break condition: If i understand your code right, then you only have the one with iterations == o. I think this means the algorithm has reached the desired depth. But what if there are no possible moves left befor the algorithm reaches this depth. Maybe you should write following:

vector<int> moves = findPossibleMoves(...);
if (!moves.size())
    return boardEval(...);
梅窗月明清似水 2024-09-23 18:07:03

在您的伪代码中,节点变量必须包含有关当前板位置(或其他)的所有信息。该信息将包括轮到谁移动。

In your pseudocode, the node variable has to contain all the information about the current board position (or whatever). This information would include whose turn it is to move.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文