Python:实现深度优先搜索Freecell Solitaire

时间:2017-05-07 07:23:37

标签: python python-3.x recursion depth-first-search

我一直在尝试使用DFS解决Freecell Solitaire游戏一个多月,现在只取得了部分成功。我是一个新手,具有非CS背景,第一个使用类和递归来解决问题,主要是试图模仿我通过Google搜索和Stack Overflow帖子发现的内容。 (关于代码清晰度等的一般性评论非常受欢迎)

游戏代码在这里:https://pastebin.com/39KGZAW1,我希望这是可以理解的。其背后的想法是:

  • 创建Board(类)的实例,类似于游戏中的快照
  • 查找所有可能的动作
  • 每次移动创建一个新实例,并使用该移动创建update(类功能)

问题是:

  • 似乎花了太长时间(当我尝试保存每块电路板时计算机内存耗尽,所以我停下来使用了发电机和双端电池),从未找到解决方案
  • 当我尝试使用mini_stacks(一张少于13张牌的牌组,目前只有1张和2张!)时,它似乎也找不到任何解决方案。
  • 与while-loop的两个实现相比,递归方法似乎更快(至少比较创建了多少Boards个实例)

更多细节:在对游戏逻辑进行编码后,我主要尝试了两种DFS方法。第一个是递归函数:

def rec(board):

    if not board.moves:
        return 
    else:
        for i in board.moves:
            new = copy.deepcopy(board) # instead of a deep copy I also tried 
            # creating a new instance taking inputs directly from the board
            globals()["it"] += 1 # for lack of a better way
            new.tt = globals()["it"]
            new.update(i)
            if new._end == True:
                raise Exception("Solved!") # didn't focus on this yet
            boards.append(new)
            rec(new)

game = Board(mini_stacks) # or full_stacks, to initialize the recursion
rec(game) # start the recursion with the game

第二种方法是使用while循环:

game = Board(mini_stacks)
boards = deque()
boards.append(game)
while boards:  

    current_search = boards.popleft()
    if current_search._end:
        print("Win")
        winning = copy.deepcopy(current_search)
        break # win

    if current_search.moves:
        for no,move in enumerate(current_search.moves):
            new = copy.deepcopy(current_search)
            it += 1
            new.tt = it
            new.update(move)
            boards.insert(no,new)

稍作修改后,我创建了一个生成器函数(也是概念的新功能)并将其用于while循环,添加了一个堆栈(= deque?):

def next_generator(boards=boards):

    if boards[0].moves:
        for no,move in enumerate(boards[0].moves):
            new = copy.deepcopy(boards[0])
            globals()["it"] += 1
            new.tt = globals()["it"]
            new.update(move)
            boards.append(new)
        yield boards.popleft()

while True:

    current_search = next(next_generator())
    if current_search._end:
        print("Win")
        winning = copy.deepcopy(current_search)
        break # win 

game = Board(mini_stacks)
boards = deque()
boards.append(game)
next_generator()

1 个答案:

答案 0 :(得分:0)

所以休息后我找到了。看起来,它不是复发,也不是while循环。我做了以下事情:

核心代码(pastebin链接)的主要变化:

  • 删除我正在检查的部分ES6 class based中的第一项是否在切片[1:]中,而是在memory函数中,只是在向{{1}附加移动之前我检查它是否已经在内存中:add_moves(为每个附加做了这个)
    • 我现在使用游戏中的牌数(堆栈中找到的最大数量)而不是硬编码胜利条件。

核心代码中的微小变化:

  • 删除了self._moves,因为没有必要
  • if move not in self.memory: self._moves.append(move)函数中,我为每张卡片和堆叠添加了一种颜色,而不是仅仅具有不同的形状。一个简单的:self.memory.append("move 0")add_moves(堆叠中每张卡的另一张卡,将卡更改为if card[2][1] in ["D","H"]: card_color = "red"

使用第二种方法(没有函数定义的else: card_color = "black"循环)我测试了各种大小的堆栈。当花费太多时间时,我停止程序,洗牌并重新运行。它发现大小为2-6的解决方案相对较快,然后7 +以上(以及创建的stack[-1][1]个对象)突然出现。我尝试了9,11和13张牌,但它没有快速找到解决方案,最终我感到无聊。

在这里你可以看到在每个牌组大小的5次重新运行(shuffle)解决方案(或停止)之前创建的板数。

Cards vs boards