2

我已经在 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 中找到的其他几个极小极大函数基本相同;我正在尝试在 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?*/
}

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

谢谢!:)

4

5 回答 5

3

来自 Wikipedia 的样本正在使用 Alpha/Beta pruning进行 NegaMax 。

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

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

  • 懒惰的程序员把它变成了 NegaMax,这是一种带有策略性-操作符的方法。

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

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

于 2010-09-02T20:02:13.917 回答
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”和一种将找到的最佳移动返回给调用者的方法。

于 2010-09-02T19:56:12.453 回答
1

playerTurn变量作为参数添加到miniMax,并miniMax以递归方式调用当前玩家的初始移动。

此外,opponentSide需要是 的函数playerTurn

于 2010-09-02T19:57:06.130 回答
1

开始搜索游戏树的一个好地方是国际象棋编程 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 变量的一点说明:极小极大或 alpha-beta 算法不需要此信息。因此,我会将信息——谁是下一个——提供给董事会结构。函数 findPossibleMoves 和 boardEval 从 Board-Structure 中获取所需的所有信息。

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

vector<int> moves = findPossibleMoves(...);
if (!moves.size())
    return boardEval(...);
于 2010-09-02T20:26:16.553 回答
0

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

于 2010-09-02T20:25:48.867 回答