【问题标题】:Maximum recursion error depth causing crash?导致崩溃的最大递归错误深度?
【发布时间】:2020-12-12 15:13:59
【问题描述】:

我正在用 tkinter 制作扫雷。我想拥有它,以便当单击一个周围有 0 个地雷的按钮时,会自动单击该按钮周围的所有按钮。但是,当我运行它并单击带有 0 的按钮时,程序崩溃了。 (最初它给了我“超出最大递归深度”的错误)。我该如何解决?完整代码如下:

import tkinter as tk
import sys
import random
from tkinter import messagebox
from PIL import Image, ImageTk
from types import FunctionType
from copy import copy

app = tk.Tk()
app.geometry("432x468")
app.title("Minesweeper")

sys.setrecursionlimit(999999999)

colors = ['#FFFFFF', '#0000FF', '#008200', '#FF0000', '#000084', '#840000', '#008284', '#840084', '#000000']

# create lists
def createlists():
    global buttonlist
    global mylist
    global numberlist
    global panelist
    global rightlist
    global flaglist
    global rowlist
    global columnlist
    global abomb
    global adic
    global secondlist
    secondlist = []
    abomb = []
    adic = {}
    buttonlist = []
    mylist = [0]
    numberlist = []
    panelist = []
    rightlist = []
    flaglist = []
    rowlist = []
    columnlist = []

    for a in range(1,18):
        mylist.append(18*a)
    
    for i in range(1,325):
        button = "b" + str(i)
        flag = 'flag' + str(i)
        row = 'row' + str(i)
        column = 'column' + str(i)
        buttonlist.append(button)
        numberlist.append(i)
        secondlist.append(i)
        flaglist.append(flag)
        rowlist.append(row)
        columnlist.append(column)

# randomly select bombs

def selectbombs():
    for i in range(0,50):
        x = "panel" + str(bomblist[i])
        panelist.append(x)
    for i in bomblist:
        n = "a" + str(i)
        abomb.append(n)
        secondlist.remove(i)
    
# create function for when a bomb is clicked

def mine():
    global bomblist
    for i in range(0,50):
        panelist[i] = tk.Label(app, image = bomb)
    for x in mylist:
        for i in range(x,x+18):
            if i+1 in bomblist:
                thing = bomblist.index(i+1)
                panelist[thing].grid(row=mylist.index(x)+1, column=i-x+1, columnspan=1)
    MsgBox = tk.messagebox.askquestion ('Game Over', 'You clicked on a bomb! Game Over. Would you like to play again?')
    if MsgBox == 'no':
        app.destroy()
    else:
        createlists()
        bomblist = random.sample(numberlist, 50)
        selectbombs()
        buttons()
        numbers()
        flags()

# create grid of buttons

def buttons():
    for i in range(0,324):
        if i+1 in bomblist:
            buttonlist[i] = tk.Button(app, text="", width=2, height=1, command=mine)
        else:
            buttonlist[i] = tk.Button(app, text="", width=2, height=1)

    for x in mylist:
        for i in range(x,x+18):
            buttonlist[i].grid(row=mylist.index(x)+1, column=i-x+1, columnspan=1)
            rowlist[i] = mylist.index(x)+1
            columnlist[i] = i-x+1

# determine the number of bombs adjacent to each button

def numbers():
    for i in range(1,325):
        adic.update({"a"+str(i) : 0})
    alist = list(adic)
    for i in bomblist:
        for x in numberlist:
            if rowlist[x-1] in range(rowlist[numberlist.index(i)]-1, rowlist[numberlist.index(i)]+2) and columnlist[x-1] in range(columnlist[numberlist.index(i)]-1, columnlist[numberlist.index(i)]+2):
                adic[alist[x-1]] = adic[alist[x-1]] + 1
    for i in bomblist:
        del adic[alist[numberlist.index(i)]]
    alist = list(adic)
    for i in adic:
        buttonlist[secondlist[alist.index(i)]-1].bind("<Button-1>", lambda event, x=secondlist[alist.index(i)]-1, y=adic[i] : num(x, y))
    
# number functions

def num(x, y):
    a = rowlist[x]
    b = columnlist[x]
    if y==0:
        buttonlist[x].config(bg = '#FFFFFF')
        buttonlist[x]["state"] = "disabled"
        if a != 1 and b != 1:
            num(x-19, adic["a"+str(x-18)])
        if a != 1:
            num(x-18, adic["a"+str(x-17)])
        if a != 1 and b != 18:
            num(x-17, adic["a"+str(x-16)])
        if b != 1:
            num(x-1, adic["a"+str(x)])
        if b != 18:
            num(x+1, adic["a"+str(x+2)])
        if a != 18 and b != 1:
            num(x+17, adic["a"+str(x+18)])
        if a != 18:
            num(x+18, adic["a"+str(x+19)])
        if a != 18 and b != 18:
            num(x+19, adic["a"+str(x+20)])
        
    else:
        buttonlist[x].config(text = y, disabledforeground = colors[y], bg = '#FFFFFF')
        buttonlist[x]["state"] = "disabled"

# create function to place a flag

im = Image.open("flag.png")
im = im.resize((20,20), Image.ANTIALIAS)
flag =  ImageTk.PhotoImage(im)

def flags():
    for i in range(0,324):
        buttonlist[i].bind("<Button-3>", lambda event, x=i : right(event, x))

def right(event, x):
    if buttonlist[x]["state"] == "normal":
        flaglist[x] = tk.Button(app, text = "", width=18, height=19, image = flag)
        flaglist[x].grid(row=rowlist[x], column=columnlist[x], columnspan=1)
        flaglist[x].bind("<Button-1>", lambda event: flaglist[x].destroy())

# check if the game has been won

def checkwin():
    disnum = 0
    for i in secondlist:
        if buttonlist[i-1]["state"] == "disabled":
            disnum = disnum + 1
    if disnum == 274:
        MsgBox = tk.messagebox.askquestion ('Game Won', 'You have won the game! Would you like to play again?')
        if MsgBox == 'no':
            app.destroy()
        else:
            createlists()
            bomblist = random.sample(numberlist, 50)
            selectbombs()
            buttons()
            numbers()
            flags()

# open images

img = Image.open("bomb.png")
img = img.resize((20,20), Image.ANTIALIAS)
bomb =  ImageTk.PhotoImage(img)

createlists()
bomblist = random.sample(numberlist, 50)
selectbombs()
buttons()
numbers()
flags()

app.mainloop()

导致程序崩溃的具体部分:

def num(x, y):
    a = rowlist[x]
    b = columnlist[x]
    if y==0:
        buttonlist[x].config(bg = '#FFFFFF')
        buttonlist[x]["state"] = "disabled"
        if a != 1 and b != 1:
            num(x-19, adic["a"+str(x-18)])
        if a != 1:
            num(x-18, adic["a"+str(x-17)])
        if a != 1 and b != 18:
            num(x-17, adic["a"+str(x-16)])
        if b != 1:
            num(x-1, adic["a"+str(x)])
        if b != 18:
            num(x+1, adic["a"+str(x+2)])
        if a != 18 and b != 1:
            num(x+17, adic["a"+str(x+18)])
        if a != 18:
            num(x+18, adic["a"+str(x+19)])
        if a != 18 and b != 18:
            num(x+19, adic["a"+str(x+20)])
        
    else:
        buttonlist[x].config(text = y, disabledforeground = colors[y], bg = '#FFFFFF')
        buttonlist[x]["state"] = "disabled"

【问题讨论】:

  • sys.setrecursionlimit(999999999) 不要这样做。 存在递归深度限制是有原因的
  • 我会检查你的逻辑,达到递归深度可能意味着你没有正确地终止你的递归逻辑。
  • 哦哈哈增加递归限制只是我正在尝试的东西,它实际上并没有工作,没有那部分也会发生同样的事情。我只是忘了从代码中删除它
  • 请提供预期的MRE。显示中间结果与预期结果的偏差。您已经向我们倾倒了近 200 行代码。减少这种情况,跟踪你的代码和数据流,并解释你在哪里得到了你没有预料到的无限递归。
  • 在我的帖子底部我列出了导致程序崩溃的具体功能

标签: python button tkinter error-handling minesweeper


【解决方案1】:

问题是在递归过程中,代码在前一个方块上回溯。检查新方块时,请确保它尚未被检查。

num函数中,添加一行代码跳过已经禁用的方块:

def num(x, y):
    if buttonlist[x]["state"] == "disabled": return  # add this line
    a = rowlist[x]
    b = columnlist[x]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-01-14
    • 1970-01-01
    • 1970-01-01
    • 2016-12-10
    • 2020-07-24
    • 2018-12-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多