Код Minesweeper, открывающий нулевые поля без максимальной глубины рекурсии - PullRequest
0 голосов
/ 01 декабря 2018

Я делаю Сапер на Python.У меня есть весь код, готовый и работающий, но я хотел бы добавить одну особенность: когда вы открываете тайл с нулями поблизости, он открывает все квадраты вокруг него.Проблема заключается в том, что если какие-либо из ящиков, которые я открываю, тоже равны нулю, им также нужно открыть все ящики вокруг них.Я считаю, что у меня есть функция, чтобы сделать это, но максимальная глубина рекурсии всегда достигается.Я пытался поднять лимит, возможно, выше, чем следовало бы, но я все еще получил ошибку.Мне было интересно, если бы это был другой способ сделать это без такой большой рекурсии.Спасибо за любую помощь, вот мой текущий код:

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 голосов
/ 01 декабря 2018

Вы можете использовать очередь .В 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) ... но это откроет самую правую ячейку во втором ряду снизу .неожиданно. Необходимо проверить, что ячейка не находится на левом краю ... перед выполнением box_open(x-1).)

Я очень уверен, что ваш исходный код можетработать, но одним из важных ключевых элементов рекурсии (или любого цикла) является обеспечение условий остановки / завершения.Это должно быть основным выводом для всех здесь (кроме реализации очереди).

...