Python 2048年Alpha-Beta的问题
我正在使用Python为2048游戏编写AI。比我想象的要慢得多。我将深度限制设置为5,但仍然需要几秒钟才能得到答案。起初我认为我所有函数的实现都是垃圾,但我找到了真正的原因。搜索树上的叶子比可能的多得多 这是一个典型的结果(我计算了树叶、树枝和展开数): 另一个很好的衡量标准是: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
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