3
\$\begingroup\$

I have just finished my minesweeper game using tkinter and would like to know how I could improve my program.

from tkinter import *
from tkinter import messagebox
from random import randint

class setupwindow():
    def __init__(window): #window is the master object of the setup window
        window.root = Tk()
        window.root.title("Setup")
        window.root.grid()

        window.finish = "N"

        labels = ["Height:", "Width:", "Mines:"]
        window.label = ["","",""]
        window.entry = ["","",""]

        for i in range(3):
            window.label[i] = Label(text = labels[i])
            window.label[i].grid(row = i, column = 1)
            window.entry[i] = Entry()
            window.entry[i].grid(row = i, column = 2)

        window.startbutton = Button(text = "Start", command = lambda: setupwindow.onclick(window))
        window.startbutton.grid(column = 2)
        window.root.mainloop()

    def onclick(window):
        setupwindow.verification(window)
        if window.verf == "Y":
            window.finish = "Y"
            window.root.destroy()
            return window

    def verification(window):
        height = window.entry[0].get()
        width = window.entry[1].get()
        mines = window.entry[2].get()

        window.verf = "N"
        if height.isdigit() and width.isdigit() and mines.isdigit():
            height = int(height)
            width = int(width)
            mines = int(mines)

            if height > 0 and height <= 24:
                totalsquares = height * width

                if width > 0 and width <= 48:

                    if mines > 0:
                        if mines < totalsquares:
                            window.verf = "Y"
                            window.height = height
                            window.width = width
                            window.mines = mines

                        else:
                            messagebox.showerror("Invalid", "You cannot have more mines than squares!")
                    else:
                        messagebox.showerror("Invalid", "You can't play minesweeper without mines!")
                else:
                    messagebox.showerror("Invalid", "Width must be between 1 and 48 inclusive")
            else:
                messagebox.showerror("Invalid", "Height must be between 1 and 24 inclusive")
        else:
            messagebox.showerror("Invalid", "All values must be integers")


class gamewindow():
    def __init__(s, setup):  #s is the master object of the main game
        s.height = setup.height
        s.width = setup.width
        s.mines = setup.mines

        s.root = Tk()
        s.root.title("Minesweeper")
        s.root.grid()

        s.finish = "N"
        s.maingrid = list()
        for i in range(s.height):
            s.maingrid.append([])
            for x in range(s.width):
                s.maingrid[i].append(" ")
                s.maingrid[i][x] = Button(height = 0, width = 3, font = "Calibri 15 bold", text = "", bg = "gray90", command = lambda i=i, x=x: gamewindow.onclick(s, i, x))

                s.maingrid[i][x].bind("<Button-3>", lambda event="<Button-3>", i=i, x=x: gamewindow.rightclick(event, s, i, x))
                s.maingrid[i][x].grid(row = i, column = x)
                s.maingrid[i][x].mine = "False"

        totalsquares = s.height * s.width
        s.scoreneeded = totalsquares - s.mines
        s.score = 0

        indexlist = list()
        for i in range(totalsquares):
            indexlist.append(i)

        spaceschosen = list() #where the mines are going to be
        for i in range(s.mines):
            chosenspace = randint(0, len(indexlist) - 1)
            spaceschosen.append(indexlist[chosenspace])
            del indexlist[chosenspace]

        for i in range(len(spaceschosen)):
            xvalue = int(spaceschosen[i] % s.width)
            ivalue = int(spaceschosen[i] / s.width)

            s.maingrid[ivalue][xvalue].mine = "True"

        s.root.mainloop()


    def onclick(s, i, x):
        colourlist = ["PlaceHolder", "Blue", "Green", "Red", "Purple", "Black", "Maroon", "Gray", "Turquoise"]

        if s.maingrid[i][x]["text"] != "F" and s.maingrid[i][x]["relief"] != "sunken":
            if s.maingrid[i][x].mine == "False":
                s.score += 1

                combinationsi = [1, -1, 0, 0, 1, 1, -1, -1]
                combinationsx = [0, 0, 1, -1, 1, -1, 1, -1] #All the surrounding spaces

                minecount = 0
                for combinations in range(len(combinationsi)):
                    tempi = i + combinationsi[combinations]
                    tempx = x + combinationsx[combinations]

                    if tempi < s.height and tempx < s.width and tempi >= 0 and tempx >= 0:
                        if s.maingrid[tempi][tempx].mine == "True":
                            minecount = minecount + 1

                if minecount == 0:
                    minecount = ""

                s.maingrid[i][x].configure(text = minecount, relief = "sunken", bg = "gray85")

                if str(minecount).isdigit():
                    s.maingrid[i][x].configure(fg = colourlist[minecount])

                if minecount == "":
                    for z in range(len(combinationsi)):
                        if s.finish == "N":
                            ivalue = i + int(combinationsi[z])
                            xvalue = x + int(combinationsx[z])

                            if ivalue >= 0 and ivalue < s.height and xvalue >=0 and xvalue < s.width:
                                if s.maingrid[ivalue][xvalue]["relief"] != "sunken":
                                    gamewindow.onclick(s, ivalue, xvalue)

                if s.score == s.scoreneeded and s.finish == "N":
                    messagebox.showinfo("Congratulations", "A winner is you!")
                    s.finish = "Y"
                    s.root.destroy()


            else:
                s.maingrid[i][x].configure(bg = "Red", text = "*")
                for a in range(len(s.maingrid)):
                    for b in range(len(s.maingrid[a])):
                        if s.maingrid[a][b].mine == "True":
                            if s.maingrid[a][b]["text"] == "F":
                                s.maingrid[a][b].configure(bg = "Green")
                            elif s.maingrid[a][b]["bg"] != "Red":
                                s.maingrid[a][b].configure(bg = "Pink", text = "*")

                        elif s.maingrid[a][b]["text"] == "F":
                            s.maingrid[a][b].configure(bg = "Yellow")

                messagebox.showinfo("GAME OVER", "You have lost")
                s.root.destroy()

    def rightclick(event, s, i, x):
        if s.maingrid[i][x]["relief"] != "sunken":
            if s.maingrid[i][x]["text"] == "":
                s.maingrid[i][x].config(text = "F")
            elif s.maingrid[i][x]["text"] == "F":
                s.maingrid[i][x].config(text = "?")
            else:
                s.maingrid[i][x].config(text = "")


if __name__ == "__main__":
    setup = setupwindow()
    if setup.finish == "Y":
        game = gamewindow(setup)
    quit()
\$\endgroup\$
2
\$\begingroup\$
  1. PEP-8

    • Class names should normally use the CapWords convention. #class-names

    • Don't use spaces around the = sign when used to indicate a keyword argument, or when used to indicate a default value for an unannotated function parameter. #whitespaces

    • Always use self for the first argument to instance methods. #function-and-method-arguments

    • There are other PEP-8 violations. Read complete document

  2. Guard clause

    What are guard clauses and how to use them?

  3. Do not use for i in range(len(list)) until you need it. Even if you need it use enumerate instead.

  4. Convert range to list

        indexlist = list()
        for i in range(totalsquares):
            indexlist.append(i)

is equivalent to indexlist = list(range(totalsquares))

\$\endgroup\$
  • \$\begingroup\$ Thanks for the feedback however I'm unsure which part of the program you are referring to when you mentioned white spaces. \$\endgroup\$ – PythonFan3362 Feb 18 at 21:56
  • \$\begingroup\$ It's about functions/constructor calls like .grid(row=i, column=x), .config(text="F") and Button(height=0, width=3, ...) \$\endgroup\$ – belkka Feb 19 at 21:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.