Python 2048年Alpha-Beta的问题

Python 2048年Alpha-Beta的问题,python,artificial-intelligence,minimax,alpha-beta-pruning,Python,Artificial Intelligence,Minimax,Alpha Beta Pruning,我正在使用Python为2048游戏编写AI。比我想象的要慢得多。我将深度限制设置为5,但仍然需要几秒钟才能得到答案。起初我认为我所有函数的实现都是垃圾,但我找到了真正的原因。搜索树上的叶子比可能的多得多 这是一个典型的结果(我计算了树叶、树枝和展开数): 另一个很好的衡量标准是: 99072 leaves, 488876 branches, 107292 expansions Branching factor: 4.55650001864 Expected max leaves = 4.556

我正在使用Python为2048游戏编写AI。比我想象的要慢得多。我将深度限制设置为5,但仍然需要几秒钟才能得到答案。起初我认为我所有函数的实现都是垃圾,但我找到了真正的原因。搜索树上的叶子比可能的多得多

这是一个典型的结果(我计算了树叶、树枝和展开数):

另一个很好的衡量标准是:

99072 leaves, 488876 branches, 107292 expansions
Branching factor: 4.55650001864
Expected max leaves = 4.55650001864^5 = 1964.06963743 leaves
正如你所看到的,搜索树上的叶子比我使用naive minimax时的叶子多得多。这是怎么回事?我的算法发布在下面:

# Generate constants
import sys
posInfinity = sys.float_info.max
negInfinity = -sys.float_info.max

# Returns the direction of the best move given current state and depth limit
def bestMove(grid, depthLimit):
    global limit
    limit = depthLimit
    moveValues = {}
    # Match each move to its minimax value
    for move in Utils2048.validMoves(grid):
        gridCopy = [row[:] for row in grid]
        Utils2048.slide(gridCopy, move)
        moveValues[move] = minValue(grid, negInfinity, posInfinity, 1)
    # Return move that have maximum value
    return max(moveValues, key = moveValues.get)

# Returns the maximum utility when the player moves
def maxValue(grid, a, b, depth):
    successors = Utils2048.maxSuccessors(grid)
    if len(successors) == 0 or limit < depth:
        return Evaluator.evaluate(grid)
    value = negInfinity
    for successor in successors:
        value = max(value, minValue(successor, a, b, depth + 1))
        if value >= b:
            return value
        a = max(a, value)
    return value
# Returns the minimum utility when the computer moves
def minValue(grid, a, b, depth):
    successors = Utils2048.minSuccessors(grid)
    if len(successors) == 0 or limit < depth:
        return Evaluator.evaluate(grid)
    value = posInfinity
    for successor in successors:
        value = min(value, maxValue(successor, a, b, depth + 1))
        if value <= a:
            return value
        b = min(b, value)
    return value
#生成常量
导入系统
posInfinity=sys.float_info.max
负无穷大=-sys.float_info.max
#返回给定当前状态和深度限制的最佳移动方向
def最佳移动(网格,深度限制):
全局极限
限制=深度限制
moveValues={}
#将每个移动与其最小最大值相匹配
对于在Utils2048中移动。有效移动(网格):
gridCopy=[row[:]表示网格中的行]
Utils2048.幻灯片(网格复制,移动)
moveValues[move]=minValue(网格,负无穷大,正无穷大,1)
#返回具有最大值的移动
返回最大值(moveValues,key=moveValues.get)
#返回玩家移动时的最大效用
def最大值(网格、a、b、深度):
继任者=Utils2048.Max继任者(网格)
如果len(后继项)=0或极限<深度:
返回评估器。评估(网格)
值=负无穷大
对于继承人中的继承人:
值=最大值(值,最小值(后续,a,b,深度+1))
如果值>=b:
返回值
a=最大值(a,值)
返回值
#返回计算机移动时的最小实用程序
def最小值(网格、a、b、深度):
继任者=Utils2048.minSuccessors(网格)
如果len(后继项)=0或极限<深度:
返回评估器。评估(网格)
值=无穷大
对于继承人中的继承人:
值=最小值(值,最大值(后续,a,b,深度+1))

如果值,则显然是将
b
(β)和
a
(α)进行比较。代码中的此比较如下所示:

def maxValue(grid, a, b, depth):
    .....
    .....
        if value >= b:
            return value
        a = max(a, value)
    return value

def最小值(网格、a、b、深度):
.....
.....
b=最小值(b,值)
如果b

这是您缺少的边缘情况,因为
a
(alpha)和
b
(beta)不一定总是等于

,您需要提供一个调用示例。。。但是试着按照这里的说明来分析它,看看你是否能识别瓶颈不管树叶的数量有多大,如果2048年的游戏只有4个动作,分支因子怎么能大于4?请告诉我们你是如何计算树叶的,分支和扩展,我们可能会帮助你。这是一篇讨论游戏的文章,也许它会有用分支因子大于4,因为这是一个对手,一个玩家进行刷卡(4个分支),另一个玩家丢弃新的磁贴,4个插槽(8个分支)中的一个可以有2或4的值。因此,对于1向前看(包括计算双方),分支因子是32。上面的代码使用了4的深度(半个look aheads),精确地说是32*32=1024。
def maxValue(grid, a, b, depth):
    .....
    .....
        if value >= b:
            return value
        a = max(a, value)
    return value
def minValue(grid, a, b, depth):
    .....
    .....
        if value <= a:
            return value
        b = min(b, value)
    return value
def maxValue(grid, a, b, depth):
    ....
    .....
        a = max(a, value)
        if a > b:
            return value

    return value
def minValue(grid, a, b, depth):
    .....
    .....
        b = min(b, value)
        if b < a:
            return value

    return value