alpha-beta修剪算法如下:
function ALPHA-BETA-SEARCH(state) returns an action
v <- MAX-VALUE(state, -∞, +∞)
return the action in ACTIONS(state) with value v
function MAX-VALUE(state, α, β) returns a utility value
if TERMINAL-TEST(state) then
return UTILITY(state)
v <- -∞
for each a in ACTIONS(state) do
v <- MAX(v, MIN-VALUE(RESULT(state, a), α, β))
if v ≥ β then
return v
α <- MAX(α, v)
return v
function MIN-VALUE(state, α, β) returns a utility value
if TERMINAL-TEST(state) then
return UTILITY(state)
v <- +∞
for each a in ACTIONS(state) do
v <- MIN(v, MAX-VALUE(RESULT(state, a), α, β))
if v ≤ α then
return v
β <- MIN(β, v)
return v
该算法指出ACTIONS
函数将给出给定state
中所有可用操作的列表。
让我们举个例子参加跳棋游戏。假设一个检查器(比如A
)与另一个检查器对齐,比如B
。如果A
可以B
,那就是(不可避免,因为我们必须采取其他检查,如果可以的话)行动。或者,如果有多个镜头,则这些都是动作。实际上可以使用铅笔和纸来绘制这种情况。更具体地说,情况可以使用树来表示,其中每个节点表示一个状态,其子节点的边表示来自该状态的可能动作。
我认为您不需要显式存储树数据结构。但是,上述算法包含以下语句:return the action in ACTIONS(state) with value v
。现在,ACTIONS(state)
将返回某个州的可能操作(例如A
需要播放的地方)。
如果我们计算出所有算法,我们将得到一个值v
,我们将跟随从终端节点传递的值为v
的节点。
现在,假设我没有存储来自每个州的所有可能移动或动作的完整树。当执行return the action ACTIONS(state) with the value v
时,我只会获得引导我进入下一个状态的动作,而且我知道其中一个动作会引导我走向最佳路径。但是,如果我没有额外的簿记,例如完整的树,我能够将值与v
?
答案 0 :(得分:4)
您不应在minimax算法中构建显式树结构,在实际情况下,不能。具有深度限制 d 和分支因子 b 的minimax算法遍历一个大的O(dᵇ)节点的树,很快得到太大而无法存放。 (在您发布的版本中,甚至没有深度限制,这意味着您将生成整个游戏树。)
跟踪状态的方法是将顶级ALPHA-BETA-SEARCH
重写为
function ALPHA-BETA-SEARCH(state) returns an action
best_a <- nil
max_v <- -∞
for each a in actions(state)
v <- MIN-VALUE(RESULT(state, a), +∞, max_v)
if v > max_v then
max_v <- v
best_a <- a
return best_a
也就是说,您在主要功能中“展开”对MAX-VALUE
的最高呼叫。
请注意,在上面的函数中,您循环遍历每个操作a
,计算他们的v
。当某个v
是您到目前为止找到的最大值时,您知道您从中计算出来的操作目前是best_a
。
答案 1 :(得分:1)
我认为有两个问题对你很重要:
无论如何构建树 - 隐含地,每个ACTIONS(vertex)
op都可以简单地将vertex
连接到他的每个儿子 - 因此无论如何都不需要额外的树构建。当然,您可以将v
等属性添加到该树的每个节点。
尽管如此,如果您不需要也不关心实际的树,一种可能的解决方案是返回(v, state)
[元组]而不仅仅是v
。关于返回值的所有操作 - 将在v
上完成,与现在相同,唯一一个实际使用state
的操作 - 是顶级ALPHA-BETA-SEARCH()
。当然,它需要不那么优雅的MIN
和MAX
函数,因为您不仅需要找到值v
- 而且还需要找到赋予此值的顶点。