简体   繁体   English

negamax算法..怎么了?

[英]The negamax algorithm..what's wrong?

I'm trying to program a chess game and have spent days trying to fix the code. 我正在尝试编写一个国际象棋游戏,并花了几天时间尝试修复该代码。 I even tried min max but ended with the same result. 我什至尝试了min max,但结果却相同。 The AI always starts at the corner, and moves a pawn out of the way then the rook just moves back and forth with each turn. AI总是从拐角处开始,将棋子移开,然后车子每转一圈就来回移动。 If it get's eaten, the AI moves every piece from one side to the other until all are eaten. 如果被食用,则AI将每一块从一侧移到另一侧,直到全部吃掉。 Do you know what could be wrong with the following code? 您知道以下代码有什么问题吗?

public Move MakeMove(int depth)
{
    bestmove.reset();
    bestscore = 0;
    score = 0;
    int maxDepth = depth;
    negaMax(depth, maxDepth);
    return bestmove;
}


public int EvalGame() //calculates the score from all the pieces on the board
{
    int score = 0;
    for (int i = 0; i < 8; i++)
    {
        for (int j = 0; j < 8; j++)
        {
            if (AIboard[i, j].getPiece() != GRID.BLANK)
            {
                score += EvalPiece(AIboard[i, j].getPiece());
            }
        }
    }

    return score;
}

private int negaMax(int depth, int maxDepth)
{
    if (depth <= 0)
    {
        return EvalGame();
    }

    int max = -200000000;

    for (int i = 0; i < 8; i++)
    {
        for (int j = 0; j < 8; j++)
        {
            for (int k = 0; k < 8; k++)
            {
                for (int l = 0; l < 8; l++)
                {
                    if(GenerateMove(i, j, k, l)) //generates all possible moves
                    {
                        //code to move the piece on the board
                        board.makemove(nextmove);
                        score = -negaMax(depth - 1, maxDepth);

                        if( score > max )
                        {
                            max = score;

                            if (depth == maxDepth)
                            {
                                bestmove = nextmove;
                            }
                        }

                        //code to undo the move
                        board.undomove;
                    }
                }
            }
        }
    }

    return max;
}

public bool GenerateMove(int i, int j, int k, int l)
{
    Move move;
    move.moveFrom.X = i;
    move.moveFrom.Y = j;
    move.moveTo.X = k;
    move.moveTo.Y = l;

    if (checkLegalMoves(move.moveTo, move.moveFrom)) //if a legal move
    {
        nextMove = move;
        return true;
    }

    return false;
}

This code: 这段代码:

public Move MakeMove(int depth)
{
    bestscore = 0;
    score = 0;
    int maxDepth = depth;
    negaMax(depth, maxDepth);
    return bestmove;
}

Notice that the best move is never set! 请注意,永远不会设置最佳动作! The return score of negaMax is compared to move alternatives. negaMax的返回得分与移动替代negaMax进行比较。 You're not even looping over the possible moves. 您甚至没有循环可能的动作。

Also, it's really hard to look for errors, when the code you submit is not fully consistent. 另外,当您提交的代码不完全一致时,很难发现错误。 The negaMax method takes two arguments one place in your code, then it take four arguments in the recursive call? negaMax方法在代码negaMax两个参数放在一个位置,然后在递归调用中将四个参数放在一个位置?

I also recommend better abstraction in your code. 我还建议在代码中使用更好的抽象。 Separate board representation, move representation, move generation, and the search algorithm. 单独的板表示,移动表示,移动生成和搜索算法。 That will help you a lot. 这将对您有很大帮助。 As an example: Why do you need the depth counter in the move generation? 例如:为什么在移动生成中需要深度计数器?

-Øystein Østein

You have two possible issues: 您有两个可能的问题:

  1. It is somewhat ambiguous as you don't show us your variable declarations, but I think you are using too many global variables. 因为您没有向我们展示您的变量声明,所以它有点模棱两可,但是我认为您使用了太多的全局变量。 Negamax works by calculating best moves at each node, and so while searching the values and moves should be local. Negamax通过计算每个节点上的最佳移动来工作,因此在搜索值时,移动应该是局部的。 In any case, it is good practice to keep the scope of variables as tight as possible. 无论如何,优良作法是保持变量的范围尽可能紧凑。 It is harder to reason about the code when traversing the game tree changes so many variables. 当遍历游戏树更改了如此多的变量时,很难对代码进行推理。 However, your search looks like it should return the correct values. 但是,您的搜索看起来应该返回正确的值。

  2. Your evaluation does not appear to discriminate which side is playing. 您的评估似乎无法区分是哪一方。 I don't know if EvalPiece handles this, but in any case evaluation should be from the perspective of whichever side currently has the right to move. 我不知道EvalPiece是否EvalPiece处理此事,但是无论如何,评估应该从当前有权移动的一方的角度进行。

You also have other issues that are not directly to your problem: 您还遇到其他与您的问题不直接相关的问题:

  1. Your move generation is scary. 您的举动令人恐惧。 You're pairwise traversing every possible pair of from/to squares on the board. 您要成对遍历板上的每对可能的从/到正方形。 This is highly inefficient and I don't understand how such a method would even work. 这是非常低效的,我什至不知道这种方法如何工作。 You need only to loop through all the pieces on the board, or for a slower method, every square on the board (instead of 4096 squares). 您只需要遍历板上的所有块,或者以较慢的方法遍历板上的每个正方形(而不是4096正方形)。

  2. MakeMove seems like it may be the place for the root node. MakeMove似乎可能是根节点的位置。 Right now, your scheme works, in that the last node the search exits from will be root. 现在,您的方案起作用了,因为搜索退出的最后一个节点将是root。 However, it is common to use special routines at the root such as iterative deepening, so it may be good to have a separate loop at the root. 但是,通常在根目录使用特殊例程(例如迭代加深),因此在根目录使用单独的循环可能会很好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM