作为一个编码项目,我想在我已经实现的基于文本的Connect4 python游戏中为用户提供某种AI。我研究过最常用的方法,而minimax是使用的主要算法。
如果我对算法的理解是正确的,我必须实现一个7-ary树,其中每个节点都有一个板状态,并且一个玩家可以从该板状态进行所有可能移动的7个子节点。
为了实现这个树,我决定使用一个Node类,它有一个子节点列表和一个当前状态。树只有3个级别,因为根据我的理解,不需要保留整个游戏的完整日志。
节点类只是:
class _Node(object):
def __init__(self, state, children=[]):
self.state = state
self.children = children
DecisionTree类是一个添加的构造函数,它将根设置为None。
但是,我想了解方法add()
如何适用于这种n-ary树。我写的代码看起来像这样:
def add(self, state):
if (self.root == None):
self.root = self._Node(state[0]) # state is a singleton list, make that state the root
else:
for i in range(len(self.root.children) + 1): # loop over all children of root
curr = self.root
while (curr.children != []): # go down in tree until we reach a leaf
curr = curr.children
for i in range(len(state)): # add all the new states
curr.children.append(state[i])
我的问题是while循环,它显然无法正常工作。它从我想要的节点变成了一个列表。我想我必须索引子项,因此将索引作为参数。然而,索引一个n-ary树会变得混乱。怎么办呢?一般来说使用列表是个坏主意吗?
答案 0 :(得分:1)
首先,请注意这个def __init__(..., children=[]):
如果您以这种方式初始化节点children
,那么代码就像这样...
a = Node(1)
b = Node(2)
print(a.children, b.children)
a.children.append(3)
print(a.children, b.children)
print(a.children is b.children) # they both point to same object in memory.
将产生此输出:
[] []
[3] [3]
True
这种情况正在发生,因为您在构造函数中提供了空列表值,并且所有实例都共享此默认值。
换句话说,在初始化具有此[]
默认子值的多个节点之后,单独节点的子节点将指向内存中的相同列表。
正确的方法是这样做:
class Node(object):
def __init__(self, state, children=None):
self.state = state
self.children = children or []
首先尝试解决此问题,看看是否有帮助。
现在关于主要问题。我的意见是,你可以在这里使用列表,但是在while循环中穿越树不是 jedi-path 。我们可以在这里使用递归。
一般情况下,我无法理解为什么你需要root,但要穿越树并添加你可以做的值:
class Node(object):
def __init__(self, state, children=None):
self.state = state
self.children = children or []
def add(self, state):
if self.children:
for node in self.children: # loop over all children of root
node.add(state) # add all the new states
else:
self.state.extend(state)
示例:
r = Node([3])
r.children = [Node([2]),Node([4]),Node([5])]
print(r.children[0].state)
r.add([25,14])
print(r.children[2].state)
# output will be
[2]
[5, 25, 14]