深度优先在Python中搜索

时间:2010-01-28 00:07:00

标签: python

好吧基本上我正在尝试深度优先搜索迷你钉单人纸牌游戏。对于那些不熟悉游戏的人来说,这非常简单。

有一个有10个孔和9个钉子的棋盘,一个钉子由一个1表示,一个空白点用一个0表示。你可以一次向前或向后移动一个钉子(但你只能移动到一个空洞)如果你在这个过程中跳过另一个钉子,你就把它拿出来然后变成一个洞。

所以这就是游戏的样子:

[1, 1, 1, 1, 1, 0, 1, 1, 1, 1]
[1, 1, 1, 0, 0, 1, 1, 1, 1, 1]
[1, 0, 0, 1, 0, 1, 1, 1, 1, 1]
[1, 0, 0, 1, 1, 0, 0, 1, 1, 1]
[1, 0, 0, 0, 0, 1, 0, 1, 1, 1]
[1, 0, 0, 0, 0, 1, 1, 0, 0, 1]
[1, 0, 0, 0, 0, 0, 0, 1, 0, 1] #etc until only 1 peg left

所以,我在这里有一个生成器函数,可以找到某个“节点”或游戏板的所有合法移动:

def succ(self, node):
    size = len(node)

    # find all legal moves going forward
    for pos in range(0, size-1):
        new_node = list(node)
        if ((node[pos] == 1) and (pos < (size - 2)) and (node[pos+2] == 0)):
            new_node[pos] = 0  # we're moving now
            new_node[pos+2] = 1 # this is where we're moving the peg to
            new_node[pos+1] = 0  # take out the peg here if there was one
            yield new_node

    # find all legal moves going backwards
    for pos in range(0, size-1):
        new_node = list(node)
        if ((node[pos] == 1) and (pos > 1) and (node[pos-2] == 0)):
            new_node[pos] = 0  # we're moving now
            new_node[pos-2] = 1 # this is where we're moving the peg
            new_node[pos-1] = 0  # take out the peg here if there was one
            yield new_node

现在,如果您知道深度优先搜索,这似乎是解决此难题时使用的GREAT生成器。或者是吗? (我想是的,也许你可以帮助提出更多的Pythonic方式?)

好吧,我使用生成器的递归拼图求解器功能不起作用,也许你可以帮帮我吗?

def goal(self, node):
    pegs = 0

    for pos in node:
        if pos == 1:
            pegs += 1

    return (pegs == 1) # returns True if there is only 1 peg

def solve_board(dfs_obj, node):
    if goal(node):  # only 1 peg!
        print node
        return node

    for new_node in succ(node):
        print new_node
        return solve_board(new_node)

if __name__ == "__main__":
    solve_board([1, 1, 1, 1, 1, 0, 1, 1, 1, 1])

所以基本上我认为我的succ()函数正在做正确的事情(可能不是吗?),但我的solve_board()递归可能很时髦,因为电路板无法解决。

2 个答案:

答案 0 :(得分:2)

由于您可以跳过空洞,因此您必须跟踪已经访问过的任何节点。否则你将有一个无限循环。

除非找到目标,否则你也不需要将for循环短路

tested_nodes=set()
def solve_board(dfs_obj, node):
    if goal(node):  # only 1 peg!
        print node
        return node

    for new_node in succ(node):
        if tuple(new_node) not in tested_nodes:
            tested_nodes.add(tuple(new_node))
            print new_node
            result = solve_board(new_node)
            if result:  # True if it's a goal, None otherwise
                return result

你的succ函数中的范围也是错误的,你不应该从范围的大小中减去1。您也可以像这样重写它以从if

中删除其中一个条件
def succ(self, node):
    size = len(node)

    # find all legal moves going forward
    for pos in range(size-2):
        new_node = list(node)
        if ((node[pos] == 1) and (node[pos+2] == 0)):
            new_node[pos] = 0  # we're moving now
            new_node[pos+2] = 1 # this is where we're moving the peg to
            new_node[pos+1] = 0  # take out the peg here if there was one
            yield new_node

    # find all legal moves going backwards
    for pos in range(1,size):
        new_node = list(node)
        if ((node[pos] == 1) and (node[pos-2] == 0)):
            new_node[pos] = 0  # we're moving now
            new_node[pos-2] = 1 # this is where we're moving the peg
            new_node[pos-1] = 0  # take out the peg here if there was one
            yield new_node

编写succ函数的另一种方法是

def succ(self, node):
    for i in range(len(node)-2):
        j=i+3
        if node[i:j]==[1,1,0]:
            yield node[:i]+[0,0,1]+node[j:]
        if node[i:j]==[0,1,1]:
            yield node[:i]+[1,0,0]+node[j:]
        if node[i:j]==[1,0,0]:
            yield node[:i]+[0,0,1]+node[j:]
        if node[i:j]==[0,0,1]:
            yield node[:i]+[1,0,0]+node[j:]

首先通过选择移除挂钉的移动来略微调整深度

答案 1 :(得分:1)

我没有对你的succ()函数进行去除,但假设它有效,那么程序的其余部分确实会进行深度优先搜索。我认为代码没有终止?如果succ可以返回先前遇到的状态,那么您可能会有一个无限的决策树,并且深度优先搜索可能会陷入无限分支并在另一个分支上错过正确的解决方案。在这种情况下,您需要使用广度优先搜索。