代码之家  ›  专栏  ›  技术社区  ›  wrongusername

C++极大极小函数

  •  2
  • wrongusername  · 技术社区  · 16 年前

    我在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 α
    

    我在谷歌中发现的几个其他的Mimax函数基本上是一样的,我试图在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?*/
    }
    

    如你所见,我对这个极大极小函数很困惑。请至少给我一些提示来帮助我。

    谢谢!:)

    5 回复  |  直到 13 年前
        1
  •  2
  •   Henk Holterman    16 年前

    维基百科的样本正在做Negamax α/β修剪 .

    您可以通过直截了当地命名来获得帮助:

    • 其基础是minimax,一个文本实现将涉及两个轮流执行的方法(相互递归),每侧1个。

    • 懒惰的程序员将其转换为negamax,这是一种具有战略性位置的方法 - 操作员。

    • alpha/beta修剪跟踪一个最佳移动窗口(多个深度),以检测死树枝。

    你的 playerTurn 用于确定轮到谁。在Negamax中,可以从奇数或偶数的深度(迭代)中得出这个结果。但使用两个参数(mycolor、othercolor)并在每个级别切换它们会更容易。

        2
  •  1
  •   Uli Schlachter    16 年前

    您的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;
      }
    

    当然,您需要一个变量“best move”和一种将找到的最佳移动返回给调用者的方法。

        3
  •  1
  •   Forrest Voight    16 年前

    添加 playerTurn 变量作为参数 miniMax 和呼叫 极大极小 当前玩家最初和递归的移动。

    也, opponentSide 必须是 游戏转弯 .

        4
  •  1
  •   Christian Ammer    16 年前

    从游戏树搜索开始的一个好地方是 chess programming wiki . 关于移动的问题:我认为最常见的是有两个max函数。两个max函数的区别在于,一个只返回分数,另一个返回分数和最佳移动。递归调用顺序如下:

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

    关于alpha-beta算法的伪代码有一些很好的论文:

    对于评论中的问题: 和math.max(alpha,score)或math.min(alpha,score)alpha是布尔值吗?!

    没有alpha是alpha-beta算法中的窗口绑定。alpha值将用新值更新。因为alpha和beta与negamax函数的递归调用交换,所以alpha变量在下一个递归调用中引用beta变量。

    playerturn变量的一个注意事项是:minimax或alpha beta算法不需要这些信息。所以我会把信息——下一个是谁——放到董事会结构中。函数findpossiblemoves和boardval从Board结构中获取所需的所有信息。

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

    vector<int> moves = findPossibleMoves(...);
    if (!moves.size())
        return boardEval(...);
    
        5
  •  0
  •   TonyK    16 年前

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