扫雷代码打开零框而没有最大递归深度

时间:2018-12-01 05:27:15

标签: python recursion minesweeper

我正在用Python开发Minesweeper。我已经完成了所有代码并可以正常工作,但是我想补充的一个功能是,当您打开附近有零个地雷的瓷砖时,它会打开周围的所有方块。问题源于以下事实:如果我打开的任何一个盒子也都是零,那么他们还需要打开它们周围的所有盒子。我相信我可以执行此操作,但是总是可以达到最大递归深度。我试图将限制提高到可能比我应有的更高,但仍然出现错误。我想知道他们是否是无需太多递归的另一种方式。感谢您的帮助,这是我当前的代码:

def open_zero(x):
    # For opening the boxes with no nearby mines
    # First, opens the box the user clicked on
    button_list[x].config(bg="#90949b")
    # Then opens all nearby boxes through the box_open function
    # I need to run these values through the function so that if they are
    # zero, they will open all nearby tiles as well.
    # This causes too much recursion.
    box_open(x+1)
    box_open(x-1)
    box_open(x+width)
    box_open(x+width+1)
    box_open(x+width-1)
    box_open(x-width)
    box_open(x-width-1)
    box_open(x-width+1)

  def box_open(x):
      if box_list[x] == "M":
          # Checks if the block is a mine
          button_list[x].config(image=photo_mine, relief = SUNKEN)
          # Stops if it was a mine
          button_frame.destroy()
          all_code()
      elif box_list[x] == 0:
          # If there are no nearby mines, open all nearby tiles.
          open_zero(x)
      else:
          # If not a mine, change button text to the amount of nearby mines.
          button_list[x].config(text=box_list[x], bg="#90949b")

希望您可以从此代码片段中了解我的代码。用我的编码方式可能是不可能的,但是如果有人有任何想法,我很想听听他们的想法。谢谢您的帮助!

1 个答案:

答案 0 :(得分:3)

您可以使用 queue 。在Python中,这可能以list的形式出现。使用.append()使项目入队,使用.pop()使项目出队。 (请注意,您不需要使用队列。您可以使用堆栈或普通列表,但是队列将模拟从点击中心散布的单元格,如果您想到一些简洁的动画,这可能会有所帮助。)

##  TODO check over this implementation
def is_open(x):
    return button_list[x].bg == "#90949b"


def open_zero(x):
    button_list[x].config(bg="#90949b")

    queue = [x]                     ##  init

    while queue:
        curr = queue.pop(0)         ##  dequeue cells here

        if is_open(curr):           ##  STOPPING CONDITION    [1]
            continue

        box_open(curr)

        if box_list[curr] != 0:     ##  checks if curr is a zero-cell, you've already implemented this previously 
            continue


        ##  enqueue nearby cells here

        # if curr >= width:         ##  STOPPING CONDITION(s) [2]
        queue.append(curr+1)        ##  TODO check curr isn't on the right edge
        queue.append(curr-1)        ##  TODO check curr isn't on the left edge
        queue.append(curr+width)    ##  TODO check curr isn't on the bottom edge
        queue.append(curr+width-1)  ##  ... 
        queue.append(curr+width+1)  ##  ... the rest has been left as an
        queue.append(curr-width)    ##  ... exercise for the reader
        queue.append(curr-width-1)
        queue.append(curr-width+1)

        ##  NOTE: without STOPPING CONDITION(s), recursion or the while-loop
        ##  will never terminate
        ##  except for the max-recursion depth 

请注意,Python会对代码中的递归感到不满的原因之一是,您没有提供任何停止终止条件。我无法强调这些的重要性。我已经部分实现了其中一个条件(is_open(x),它检查单元格x是否打开)。

由于这是扫雷器,我假设您正在矩阵/网格上进行此操作(但将按钮存储在列表中)。不过,您仍然需要检查网格的边界,否则您的递归会跳过网格壁或做其他奇怪的事情。

(想法实验:想象一下,单击网格的左下角单元。这将触发box_open(x)。这又将触发box_open(x-1)queue.append(curr-1)。 ,但是它们会打开位于底部第二行中的最右边的单元格。这是意外的。您需要检查该单元格不在左侧...执行{{1 }}。)

高度确信您的原始代码可以工作,但是递归(或任何循环)的重要关键要素之一就是提供停止/终止条件。除了队列的实现,这应该是每个人的主要收获。