-1

I'm making Minesweeper with tkinter. I want to have it so that when a button with 0 mines surrounding it is clicked, all the buttons around that one are automatically clicked. However, when I run this and click on a button with 0, the program crashes. (originally it gave me the error of "maximum recursion depth exceeded"). How do I fix this? Here is the full code:

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()

the specific part which is causing the program to crash:

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"
rnbw10
  • 1
  • 1
  • 4
    `sys.setrecursionlimit(999999999)` don't do this. The recursion depth limit is *there for a reason*. – juanpa.arrivillaga Aug 24 '20 at 00:26
  • 3
    I would check your logic, hitting the recursion depth could mean you a not correctly terminating your recursion logic. – AChampion Aug 24 '20 at 00:27
  • 1
    oh haha increasing the recursion limit was just something i was trying out, it didn't actually work and the same thing happens without that part. i just forgot to remove it from the code – rnbw10 Aug 24 '20 at 00:28
  • 1
    Please provide the expected [MRE](https://stackoverflow.com/help/minimal-reproducible-example). Show where the intermediate results deviate from the ones you expect. You've dumped nearly 200 lines of code on us. Reduce this, trace your code and data flows, and explain where you get infinite recursion that you didn't expect. – Prune Aug 24 '20 at 00:32
  • at the bottom of my post i have listed the specific function that causes the program to crash – rnbw10 Aug 24 '20 at 00:33
  • While python can do recursion, it isn't optimized for it. The default depth limit is something like 50. So you should have a clear idea of deep it will go. If necessary add diagnostic prints to track the recursion, and detect why it isn't stopping. – hpaulj Aug 24 '20 at 00:51

1 Answers1

0

The issue is that in the recursion process, the code is backtracking on previous squares. When checking a new square, be sure it has not already be checked.

In the num function, add a line of code to skip squares that have already been disabled:

def num(x, y):
    if buttonlist[x]["state"] == "disabled": return  # add this line
    a = rowlist[x]
    b = columnlist[x]
Mike67
  • 11,175
  • 2
  • 7
  • 15