Search code examples
pythontkinterminesweeper

How to avoid a mine being hit first in a tkinter version of minesweeper?


Okay, now I have made a piece of code alongside my programming skills developing, so excuse the shoddy coding, and the majority of my code being included, due to me not knowing how to cut it down with it still working and making sense. Any edits to cut it down would be appreciated.

The problem is that my minesweeper game sometimes allows it to hit a mine first round, and I need to make sure this isn't a possibility, it constantly crashes each time I attempt my solution. The idea was that if self.Counter was "start" and the first clicked one was a mine, it would reset the grid, but it crashed. Any ideas?

from tkinter import *
import random
import time


#==================================================================================================
root=Tk()
#==================================================================================================

class GridGame(Toplevel):
    def __init__(self,master):
        self.fr=Toplevel(master)
        self.TotalFrame=Frame(self.fr,bg="black")
        self.ButtonColor="red"
        self.GameFrame=Frame(self.TotalFrame,bg="white")
        self.AllButtons=[]
        self.MineGrid=[]
        self.SizeGrid=17
        self.Mines=50
        self.MarkedMineColour="blue"
        self.Counter="Start"
        for x in range(self.SizeGrid):
            Column=[]
            MineColumn=[]
            for y in range(self.SizeGrid):
                item=Button(self.GameFrame,bg=self.ButtonColor,text="",height=2, width=6)
                item.bind("<Button-3>",self.ChoiceChange)
                Column.append(item)
                MineColumn.append("")
            self.AllButtons.append(Column)
            self.MineGrid.append(MineColumn)
        self.GameFrame.grid(row=0,column=0,pady=15,padx=20,columnspan=2)
        self.Quit=Button(self.TotalFrame, text="Destroy This Game", bg="orange",command=self.fr.destroy)
        self.Restart=Button(self.TotalFrame, text="Reset This Game", bg="light blue",command=self.Reset)
        self.Quit.grid(row=1,column=0,pady=5,padx=10)
        self.Restart.grid(row=1,column=1,pady=5,padx=10)
        self.TotalFrame.pack()


        for x in range(self.SizeGrid):
            for y in range(self.SizeGrid):
                    self.AllButtons[x][y].configure(command=lambda a=self.AllButtons[x][y],c=x,d=y:self.ColorFlip(a,c,d))
                    self.AllButtons[x][y].grid(row=x,column=y,padx=5,pady=5)
##        w = self.fr.winfo_screenwidth()
##        h = self.fr.winfo_screenheight()
        self.fr.geometry('%dx%d+%d+%d' % (1100, 950, 300, 10))
#==================================================================================================
    def MineGridMaker(self):
        for x in range(0,self.Mines):
                choice1,choice2=random.choice(range(0,len(self.AllButtons))),random.choice(range(0,len(self.AllButtons)))
                if self.MineGrid[choice1][choice2]=="":
                    self.MineGrid[choice1][choice2]="M"
        for x in range(0,len(self.AllButtons)):
            for y in range(0,len(self.AllButtons)):
                if self.MineGrid[x][y]=="M":
                    for xx in range(x-1,x+2):
                        for yy in range(y-1,y+2):
                            if xx in range(0,self.SizeGrid) and yy in range(0,self.SizeGrid):
                                if self.MineGrid[xx][yy]!="M" and self.MineGrid[xx][yy]=="":
                                    self.MineGrid[xx][yy]="1"
                                elif self.MineGrid[xx][yy]!="M" and int(self.MineGrid[xx][yy])>=1:
                                    self.MineGrid[xx][yy]=str(int(self.MineGrid[xx][yy])+1)
#==================================================================================================
    def ColorFlip(self,Object,x,y):
        if self.Counter==self.SizeGrid**2-self.Mines:
            MineGridMaker()
        if Object["bg"]==self.ButtonColor:
            if self.MineGrid[x][y]=="M":
                for Item in range(0,len(self.AllButtons)):
                    for item in range(0,len(self.AllButtons)):
                        self.AllButtons[Item][item].configure(bg="grey",text=self.MineGrid[Item][item])
                Object.configure(bg="red",text=self.MineGrid[x][y])
                for a in range(x-1,x+2):
                    for b in range(y-1,y+2):
                        if a in range(0,self.SizeGrid) and b in range(0,self.SizeGrid):
                            root.after(200,self.BlowUp,a,b)
            else:
                self.Counter-=1
                if self.MineGrid[x][y]=="":
                    for a in range(x-1,x+2):
                        for b in range(y-1,y+2):
                            if a in range(0,self.SizeGrid) and b in range(0,self.SizeGrid):
                                if self.AllButtons[a][b]["bg"]==self.ButtonColor:
                                    Object.configure(bg="white",text=self.MineGrid[x][y])
                                    self.ColorFlip(self.AllButtons[a][b],a,b)
                else:
                    Object.configure(bg="white",text=self.MineGrid[x][y])
        if self.Counter<=0:
            for a in range(0,(self.SizeGrid)):
                for b in range(0,(self.SizeGrid)):
                    if self.MineGrid[a][b]=="M":
                        self.AllButtons[a][b].configure(text=self.MineGrid[a][b],bg="orange")
                    else:
                        self.AllButtons[a][b].configure(bg="light green")
#==================================================================================================
    def BlowUp(self,x,y):
        for a in range(1,21):
            root.after((75*a)-25,self.Flash1,x,y)
            root.after(75*a,self.Flash2,x,y)
        root.after(1800,self.Fade,x,y)

    def Flash1(self,x,y):
        try:
            if self.AllButtons[x][y]["bg"]!=self.ButtonColor:
                self.AllButtons[x][y].configure(bg="orange")
        except:
            pass

    def Flash2(self,x,y):
        try:
            if self.AllButtons[x][y]["bg"]!=self.ButtonColor:
                self.AllButtons[x][y].configure(bg="yellow")
        except:
            pass

    def Fade(self,x,y):
        try:
            if self.AllButtons[x][y]["bg"]!=self.ButtonColor or self.AllButtons[x][y]["text"]!="":
                self.AllButtons[x][y].configure(bg="white")
        except:
            pass

    def Reset(self):
        for x in self.AllButtons:
            for y in x:
                y.configure(bg=self.ButtonColor,text="")
        self.Counter=(self.SizeGrid**2)-self.Mines

    def ChoiceChange(self,event):
        if event.widget["bg"]==self.ButtonColor:
            event.widget["bg"]=self.MarkedMineColour
        elif event.widget["bg"]==self.MarkedMineColour:
            event.widget["bg"]=self.ButtonColor

Solution

  • Start with self.Counter being "Start". When ColourFlip is being called, let it check if self.Counter is start, if so, then create the mine grid with the x and y coords being brought in as parameters, and keeping that clicked button as not a mine. Then it should just carry on allowing you to die if there is a mine.

    There is the issue of it being reset, it stays the exact same as the last game, so yeah. Might be good, or not.

    from tkinter import *
    import random
    import time
    
    
    #==================================================================================================
    root=Tk()
    #==================================================================================================
    
    class GridGame(Toplevel):
        def __init__(self,master):
            self.fr=Toplevel(master)
            self.TotalFrame=Frame(self.fr,bg="black")
            self.ButtonColor="red"
            self.GameFrame=Frame(self.TotalFrame,bg="white")
            self.AllButtons=[]
            self.MineGrid=[]
            self.SizeGrid=17
            self.Mines=50
            self.MarkedMineColour="blue"
            self.Counter="Start"
            for x in range(self.SizeGrid):
                Column=[]
                MineColumn=[]
                for y in range(self.SizeGrid):
                    item=Button(self.GameFrame,bg=self.ButtonColor,text="",height=2, width=6)
                    item.bind("<Button-3>",self.ChoiceChange)
                    Column.append(item)
                    MineColumn.append("")
                self.AllButtons.append(Column)
                self.MineGrid.append(MineColumn)
            self.GameFrame.grid(row=0,column=0,pady=15,padx=20,columnspan=2)
            self.Quit=Button(self.TotalFrame, text="Destroy This Game", bg="orange",command=self.fr.destroy)
            self.Restart=Button(self.TotalFrame, text="Reset This Game", bg="light blue",command=self.Reset)
            self.Quit.grid(row=1,column=0,pady=5,padx=10)
            self.Restart.grid(row=1,column=1,pady=5,padx=10)
            self.TotalFrame.pack()
    
    
            for x in range(self.SizeGrid):
                for y in range(self.SizeGrid):
                        self.AllButtons[x][y].configure(command=lambda a=self.AllButtons[x][y],c=x,d=y:self.ColorFlip(a,c,d))
                        self.AllButtons[x][y].grid(row=x,column=y,padx=5,pady=5)
    ##        w = self.fr.winfo_screenwidth()
    ##        h = self.fr.winfo_screenheight()
            self.fr.geometry('%dx%d+%d+%d' % (1100, 950, 300, 10))
    #==================================================================================================
        def MineGridMaker(self,a="a",b="a"):
            for x in range(0,self.Mines):
                CarryOn=False
                while CarryOn==False:
                    choice1,choice2=random.choice(range(0,len(self.AllButtons))),random.choice(range(0,len(self.AllButtons)))
                    if self.MineGrid[choice1][choice2]=="":
                        if a!=choice1 or b!=choice2:
                            self.MineGrid[choice1][choice2]="M"
                            CarryOn=True
    
            for x in range(0,len(self.AllButtons)):
                for y in range(0,len(self.AllButtons)):
                    if self.MineGrid[x][y]=="M":
                        for xx in range(x-1,x+2):
                            for yy in range(y-1,y+2):
                                if xx in range(0,self.SizeGrid) and yy in range(0,self.SizeGrid):
                                    if self.MineGrid[xx][yy]!="M" and self.MineGrid[xx][yy]=="":
                                        self.MineGrid[xx][yy]="1"
                                    elif self.MineGrid[xx][yy]!="M" and int(self.MineGrid[xx][yy])>=1:
                                        self.MineGrid[xx][yy]=str(int(self.MineGrid[xx][yy])+1)
    #==================================================================================================
        def ColorFlip(self,Object,x,y):
            if self.Counter=="Start":
                self.Counter=(self.SizeGrid**2)-self.Mines
                self.MineGridMaker(x,y)
            if Object["bg"]==self.ButtonColor:
                if self.MineGrid[x][y]=="M":
                    for Item in range(0,len(self.AllButtons)):
                        for item in range(0,len(self.AllButtons)):
                            self.AllButtons[Item][item].configure(bg="grey",text=self.MineGrid[Item][item])
                    Object.configure(bg="red",text=self.MineGrid[x][y])
                    for a in range(x-1,x+2):
                        for b in range(y-1,y+2):
                            if a in range(0,self.SizeGrid) and b in range(0,self.SizeGrid):
                                root.after(200,self.BlowUp,a,b)
                else:
                    self.Counter-=1
                    if self.MineGrid[x][y]=="":
                        for a in range(x-1,x+2):
                            for b in range(y-1,y+2):
                                if a in range(0,self.SizeGrid) and b in range(0,self.SizeGrid):
                                    if self.AllButtons[a][b]["bg"]==self.ButtonColor:
                                        Object.configure(bg="white",text=self.MineGrid[x][y])
                                        self.ColorFlip(self.AllButtons[a][b],a,b)
                    else:
                        Object.configure(bg="white",text=self.MineGrid[x][y])
            if self.Counter<=0:
                for a in range(0,(self.SizeGrid)):
                    for b in range(0,(self.SizeGrid)):
                        if self.MineGrid[a][b]=="M":
                            self.AllButtons[a][b].configure(text=self.MineGrid[a][b],bg="orange")
                        else:
                            self.AllButtons[a][b].configure(bg="light green")
    #==================================================================================================
        def BlowUp(self,x,y):
            for a in range(1,21):
                root.after((75*a)-25,self.Flash1,x,y)
                root.after(75*a,self.Flash2,x,y)
            root.after(1800,self.Fade,x,y)
    
        def Flash1(self,x,y):
            try:
                if self.AllButtons[x][y]["bg"]!=self.ButtonColor:
                    self.AllButtons[x][y].configure(bg="orange")
            except:
                pass
    
        def Flash2(self,x,y):
            try:
                if self.AllButtons[x][y]["bg"]!=self.ButtonColor:
                    self.AllButtons[x][y].configure(bg="yellow")
            except:
                pass
    
        def Fade(self,x,y):
            try:
                if self.AllButtons[x][y]["bg"]!=self.ButtonColor or self.AllButtons[x][y]["text"]!="":
                    self.AllButtons[x][y].configure(bg="white")
            except:
                pass
    
        def Reset(self):
            for x in self.AllButtons:
                for y in x:
                    y.configure(bg=self.ButtonColor,text="")
            self.Counter=(self.SizeGrid**2)-self.Mines
    
        def ChoiceChange(self,event):
            if event.widget["bg"]==self.ButtonColor:
                event.widget["bg"]=self.MarkedMineColour
            elif event.widget["bg"]==self.MarkedMineColour:
                event.widget["bg"]=self.ButtonColor