当前位置: 首页 > 知识库问答 >
问题:

用Alpha-Beta修剪迭代加深Negamax

万志专
2023-03-14

我的程序中有一个有效的negamax算法。然而,我需要程序在kMaxTimePerMove时间内找到最佳移动。我做了一些研究,似乎用我的negamax算法进行迭代深化是最好的方法。现在,我启动搜索的函数如下所示:

// this is a global in the same scope as the alpha-beta functions, so they can check the elapsed time
clock_t tStart;

int IterativeDeepening(Board current_state)
{
    bool overtime = false;
    int depth = 0;
    tStart = clock();

    MoveHolder best_move(-1, kWorstEvaluation);

    while ((static_cast<double> (clock() - tStart)/CLOCKS_PER_SEC) < kMaxTimePerMove)
    {
        MoveHolder temp_move = AlphaBetaRoot(kWorstEvaluation, -best_move.evaluation_,++depth, current_state, overtime);          
        if (!overtime)
            best_move = temp_move;
    }

    return best_move.column_;
}

我想我也应该重新排序之前的最佳移动到儿童列表的前面,但是,我在等待实现,直到我得到基本版本的工作。实际的阿尔法-贝塔函数是这样的:

MoveHolder AlphaBetaRoot(int alpha, int beta, int remaining_depth, Board current_state, bool &overtime)
{
    MoveHolder best(-1, -1);
    if (overtime)
        return MoveHolder(0,0);

    std::vector<Board> current_children;
    current_state.GetBoardChildren(current_children);

    for (auto i : current_children)
    {
        best.evaluation_ = -AlphaBeta(-beta, -alpha, remaining_depth - 1, i, overtime);
        if ((static_cast<double> (clock() - tStart)/CLOCKS_PER_SEC) > kMaxTimePerMove)
        {
            overtime = true;
            return MoveHolder(0,0);
         }
        if (best.evaluation_ >= beta)
            return best;
        if (best.evaluation_ > alpha)
        {
            alpha = best.evaluation_;
            best.column_ = i.GetLastMoveColumn();
        }
    }
    return best;
}

int AlphaBeta(int alpha, int beta, int remaining_depth, Board2 current_state, bool &overtime)
{
    if (overtime)
        return 0;
    if ((static_cast<double> (clock() - tStart)/CLOCKS_PER_SEC) > kMaxTimePerMove)
    {
        overtime = true;
        return 0;
    }

    if (remaining_depth == 0 || current_state.GetCurrentResult() != kNoResult)
    {
        return current_state.GetToMove() * current_state.GetCurrentEvaluation();
    }


    std::vector<Board> current_children;
    current_state.GetBoardChildren(current_children);
    for (auto i : current_children)
    {
        int score = -AlphaBeta(-beta, -alpha, remaining_depth - 1, i, overtime);
        if (score >= beta)
        {
            return beta;
        }
        if (score > alpha)
        {
            alpha = score;
        }
    }
    return alpha;
}

当我尝试调试时,一切似乎都在按预期工作。然而,当我将迭代深化版本与常规的alphabeta实现进行比较时,它总是会失败。有时,它似乎会“卡住”,并返回一个可怕的动作。

举个例子,如果这个程序被“强迫”在下一个回合移动,否则对手会赢,它不会阻止胜利。在那一步,它报告说它正在搜索到38的深度。我发现这个算法极难调试,因为如果我破坏了执行,它就破坏了时间。

我不确定我是否错误地实现了算法,或者只是这里有一个棘手的错误。如果有人能给我指出正确的方向,我将不胜感激。

共有1个答案

荀学文
2023-03-14

您使用 -best_move.evaluation_ 作为搜索的 beta 值,其中best_move是与上一个深度相比的最佳移动。这是不正确的:假设一个移动在深度=2时看起来不错,但在更大的深度下结果很糟糕。这种方法将继续认为它很好,并导致在其他移动中不应该发生的 beta 截止。

您应该搜索每个迭代(-infinity,infinity)来解决此问题。您还可以使用抽吸窗口来限制 α-β 范围。

请注意,由于您不使用上一个迭代来改进下一个迭代的移动顺序,因此迭代深化将导致结果稍差。理想情况下,您希望移动排序从换位表和/或上一次迭代的主变体中选择最佳移动。

 类似资料:
  • 如何知道何时可以停止增加使用negamax alpha beta修剪和换位表的迭代深化算法的深度?以下伪代码取自wiki页面: 这是迭代深化调用: 当然,当我知道游戏中的总移动次数时,我可以使用深度

  • 我正在用Java做一个国际象棋游戏,并且(我认为)已经成功地为AI玩家实现了Negamax。我在添加阿尔法贝塔剪枝来改进算法时遇到了一些麻烦。我已经尝试了下面的教程和示例代码,但就是不明白它是如何工作的。 以下是我目前必须获得最佳移动的代码: 这是我尝试将aplha-beta修剪添加到我的(工作)内切方法中: 最后是控制台的外观 任何帮助都将不胜感激。提前感谢。

  • 我已经实现了一个带有alpha beta修剪的NegaMax算法(这只是一个较短版本的极小值算法)。现在我想实现迭代深化,这样我就可以为每个深度找到最佳移动,然后根据之前层的分数重新排序树下的节点,以便我的alphabeta修剪工作更有效。 以下是我迄今为止所做的工作: 这里gs是随每一步移动而变化的游戏属性,包含了所有关于游戏在t点的信息,比如是否可以施法或者是否有可能的内移。我的egamax算

  • 我正在尝试为跳棋游戏(AI vs AI)编写一个使用阿尔法-贝塔修剪的算法。你可以看到代码 游戏本身运行良好,但人工智能(阿尔法-贝塔修剪算法)似乎有一个错误,因为机器人基本上是互相喂食跳棋(根本没有计算显示)。代码包含2个不同版本的alpha-beta算法函数(更详细和不太详细)。 我试过在中跟踪的值,它似乎有正常值(在深度=5的情况下范围为-3到3)。 我也尝试过在我的代码中实现此代码,但得到

  • 我试图让Alpha-beta修剪工作,但与我的Minimax函数相比,它给了我完全错误的动作。这是我的极大极小函数,它现在工作得很好。 这是我的Alphabeta修剪函数 两者都使用相同的评估,不确定这里出了什么问题。谢谢你的帮助。

  • 我目前正在从事我的第一个C项目,并选择使用基于Minimax的AI编写一个Connect Four(又名Score 4),更具体地说是基于Alpha-Beta修剪方法。 到目前为止,我了解到AB修剪包含在一个递归算法中,该算法考虑了一个alpha和一个beta参数,这是您在游戏树中找不到的“极限”。此外,我们定义了最大化和最小化玩家,前者是第一个开始玩游戏的玩家。最后,还有一个“深度”,我把它理解