Skip to content
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
"""Minesweeper"""
### --- LIBRARIES/MODULES USED + INITIALIZATION --- ###
### Tkinter
from tkinter import *
root=Tk()
root.title('Minesweeper')
### Random
import random
### --- CORE FUNCTION EXPLANATIONS --- ###
### lock() - puts game in locked state for game over/win conditions
### reveal(button number, red mine number carried from click) - reveal of multiple buttons at once, text number colours
### click(button number) - initial response to click
### check_win() - check if winning condition is met
### flag(event, button number) - associated with flag placement and removal using right click ('<Button-3>')
### button_creation() - creates w*h grid with m mines, binds relevant commands onto left and right clicks
### adjacent(button number, algorithm type) - counts adjacent mines/zero tiles
### setter(button number, adjacency counter, algorithm type) - sets adjacency counter to mines or blocks, used within adj algorithm
### adjacency_algorithm(button number, algorithm type) - sets adjacent mines of tile or assigns block
### restart() - resets board to initial appearance
### newgame() - generates new board
### [REMOVED] settings() - opens settings window
### --- SECONDARY FUNCTIONS --- ###
### num_mines(mines) - creates specified number of mines (returns random numbers within grid size)
### make_lambda(i) - lambda for right click binding
### middle(width, height) - list of grid positions not on the edge
### zeros_func() - list of grid positions with zero mines in adjacency
### blocks_func() - list of grid positions a block assigned
### colours(button number) - configs button text to corresponding colour (cosmetic function)
### window_geometry(width, height) - makes window fit for given grid size
### check_size(integer) - ensures w,h,m are not below 10, if they are, 10 is returned
### line_loop(width, height) - grid number sequences used for chunk setting
### [REMOVED] make_int() - sets w,h,m to int (used for conversion after entry widget in settings)
### --- BUTTON DICTIONARY INDEX REFERENCE --- ###
button={}
### button[i][0]= Button Configuration
### button[i][1]= Grid Position
### button[i][2]= Mine presence or mine adjacency
### button[i][3]= Flag placement ("F"/"")
### button[i][4]= Block
### --- GRID VARIABLES --- ###
### Change w and h for different grid size
### Change m for number of mines
### Recommended: w/h<50 + m<20 for best performance
w=20
h=20
m=50
### FONT
f = (" Courier ", 24, "bold")
### --- FUNCTIONS (CORE + SECONDARY) --- ###
def check_size(i):
if i<10:
return 10
return i
def window_geometry(w,h):
width=((w-10)*24)+240
height=((h-10)*26)+339
geo=str(width)+"x"+str(height)
return geo
def lock():
for i in button:
button[i][0].configure(command=lambda i=i:None)
button[i][0].bind('<Button-3>', lambda i=i: None)
def reveal(i, num):
global blocks
if button[i][2]=="M" and i!=num:
button[i][0].configure(text="M", bg="orange")
label.config(text="Game Over")
elif button[i][2]==0:
temp=button[i][4]
for i in button:
if button[i][3]=="F":
pass
elif button[i][4]==temp:
colours(i)
else:
colours(i)
def colours(i):
if button[i][2]==0: button[i][0].configure(bg="ivory4")
elif button[i][2]==1: button[i][0].configure(fg="cornflower blue",text=button[i][2],bg="ivory3")
elif button[i][2]==2: button[i][0].configure(fg="forest green",text=button[i][2],bg="ivory3")
elif button[i][2]==3: button[i][0].configure(fg="red",text=button[i][2],bg="ivory3")
elif button[i][2]==4: button[i][0].configure(fg="medium blue",text=button[i][2],bg="ivory3")
elif button[i][2]==5: button[i][0].configure(fg="red4",text=button[i][2],bg="ivory3")
def click(num):
button[num][0].configure(bg='ivory3')
check_win()
if button[num][2]== "M":
button[num][0].configure(text="M", bg="red")
label.config(text="M")
print("Game Over\n")
for i in button:
if button[i][2]=="M":
reveal(i, num)
lock()
else:
reveal(num, None)
def check_win():
mine_positions=[]
blue_count=0
mine_count=0
for i in button:
if button[i][0]["bg"]=="light sky blue":
blue_count+=1
if button[i][2]=="M":
mine_positions.append(i)
mine_count+=1
if mine_count==blue_count:
label.config(text="Win")
print("Win\n")
for i in mine_positions:
button[i][0].configure(bg="lawn green")
lock()
def num_mines(m):
mines=[]
counter=0
while counter<m:
randombit=random.randint(0,w*h)
if randombit not in mines:
mines.append(randombit)
counter+=1
return mines
def flag(event,i):
global flags
if button[i][0]["bg"]=="ivory3" or button[i][0]["bg"]=="ivory4":
return None
else:
if button[i][3]=="F":
button[i][0].configure(text="",command= lambda i=i: click(i))
button[i][3]=""
flags+=1
elif button[i][3]=="" and flags!=0:
button[i][0].configure(text="F",command= lambda i=i: None)
button[i][3]="F"
flags-=1
label.config(text=flags)
def make_lambda(i):
return lambda event: flag(event, i)
def button_creation():
c=0
for j in range(h):
j=Frame(root)
j.pack()
for i in range(0+c,w+c):
button[i]=[Button(j, text="", bg='light sky blue', width=2, command=lambda i=i: click(i)), i, "", "", ""]
button[i][0].bind('<Button-3>', make_lambda(i))
if i in mines:
button[i][2]="M"
button[i][4]="B"
if i in range((w*h)-w,w*h):
button[i][0].pack(pady=0, side=LEFT)
else:
button[i][0].pack(side=LEFT)
c=c+w
def middle(w,h):
middle=[]
q=0
for k in range(h-2):
for i in range((w+1)+q,(w*2)-1+q):
middle.append(i)
q=q+w
return middle
def adjacent(i, TYPE):
if button[i][2]==0 and TYPE=="SET_BLOCK":
return 1
elif button[i][2]=="M" and TYPE=="SET_MINE":
return 1
elif TYPE=="SET_BLOCK" or TYPE=="SET_MINE":
return 0
elif TYPE=="SET_CHUNKS":
global surround
surround.append(button[i][4])
return 1
else:
return 0
def zeros_func():
zeros=[]
for i in button:
if button[i][2]==0:
zeros.append(i)
return zeros
def blocks_func():
blocks=[]
for i in button:
if button[i][4]=="B":
blocks.append(i)
return blocks
def adjacent_algorithm(i, TYPE):
c=0
if button[i][1]==0 and button[i][2]!="M": #TOP LEFT CORNER (0)
c+=adjacent(i+1, TYPE)
c+=adjacent(i+w, TYPE)
c+=adjacent(i+w+1, TYPE)
setter(i, c, TYPE)
elif button[i][1]==w-1 and button[i][2]!="M": #TOP RIGHT CORNER
c+=adjacent(i-1, TYPE)
c+=adjacent(i+w-1, TYPE)
c+=adjacent(i+w, TYPE)
setter(i, c, TYPE)
elif button[i][1]==(w*h)-w and button[i][2]!="M": #BOTTOM LEFT
c+=adjacent(i+1, TYPE)
c+=adjacent(i-w, TYPE)
c+=adjacent(i-w-1, TYPE)
setter(i, c, TYPE)
elif button[i][1]==(w*h)-1 and button[i][2]!="M": #BOTTOM RIGHT
c+=adjacent(i-1, TYPE)
c+=adjacent(i-w, TYPE)
c+=adjacent(i-w-1, TYPE)
setter(i, c, TYPE)
elif button[i][1] in range(1,w-1) and button[i][2]!="M": #TOP ROW
c+=adjacent(i-1, TYPE)
c+=adjacent(i+1, TYPE)
c+=adjacent(i+w-1, TYPE)
c+=adjacent(i+w, TYPE)
c+=adjacent(i+w+1, TYPE)
setter(i, c, TYPE)
elif button[i][1] in range((w*h)-(w-1),(w*h)-1) and button[i][2]!="M": #BOTTOM ROW
c+=adjacent(i-w-1, TYPE)
c+=adjacent(i-w, TYPE)
c+=adjacent(i-w+1, TYPE)
c+=adjacent(i-1, TYPE)
c+=adjacent(i+1, TYPE)
setter(i, c, TYPE)
elif button[i][1] in range(w,(w*h)-(w-1),w) and button[i][2]!="M": #LEFT COLUMN
c+=adjacent(i-w, TYPE)
c+=adjacent(i-w+1, TYPE)
c+=adjacent(i+1, TYPE)
c+=adjacent(i+w, TYPE)
c+=adjacent(i+w+1, TYPE)
setter(i, c, TYPE)
elif button[i][1] in range((w*2)-1,(w*h)-w,w) and button[i][2]!="M": #RIGHT COLUMN
c+=adjacent(i-w-1, TYPE)
c+=adjacent(i-w, TYPE)
c+=adjacent(i-1, TYPE)
c+=adjacent(i+w-1, TYPE)
c+=adjacent(i+w, TYPE)
setter(i, c, TYPE)
elif button[i][1] in middle and button[i][2]!="M":
c+=adjacent(i-w-1, TYPE)
c+=adjacent(i-w, TYPE)
c+=adjacent(i-w+1, TYPE)
c+=adjacent(i-1, TYPE)
c+=adjacent(i+1, TYPE)
c+=adjacent(i+w-1, TYPE)
c+=adjacent(i+w, TYPE)
c+=adjacent(i+w+1, TYPE)
setter(i, c, TYPE)
if TYPE=="SET_BLOCK" and button[i][2]==0:
button[i][4]=""
def setter(i, c, TYPE):
if TYPE is "SET_MINE":
button[i][2]=c
elif TYPE is "SET_BLOCK":
if c==0:
button[i][4]="B"
else:
button[i][4]=""
elif TYPE is "SET_CHUNKS":
global surround,n
if button[i][4]=="B":
surround=[]
return None
for k in surround:
if "C" in k:
button[i][4]=k
break
else: pass
if "C" not in button[i][4]:
chunk="C"+str(n)
n+=1
button[i][4]=chunk
surround=[]
def restart():
print("Restarting Game...")
for i in button:
button[i][0].configure(text="", bg="light sky blue", fg="black", command=lambda i=i: click(i))
button[i][0].bind('<Button-3>', make_lambda(i))
button[i][3]=""
global flags
flags=len(mines)
label.config(text=flags)
print("Restart Complete\n")
def newgame():
print("Generating New Game...")
global zeros,blocks, mines, flags
flags=len(mines)
label.config(text=flags)
mines=num_mines(m)
for i in button:
button[i][0].configure(text="",bg="light sky blue", fg="black", command=lambda i=i: click(i))
button[i][0].bind('<Button-3>', make_lambda(i))
button[i][2]=""
button[i][3]=""
button[i][4]=""
if i in mines:
button[i][2]="M"
button[i][4]="B"
button[i][0].pack(side=LEFT)
for i in line_loop:
adjacent_algorithm(i, "SET_MINE")
zeros=zeros_func()
for i in line_loop:
adjacent_algorithm(i, "SET_BLOCK")
blocks=blocks_func()
for i in line_loop:
adjacent_algorithm(i, "SET_CHUNKS")
print("Generation Complete\n")
##def settings(w,h,m):
## r=Toplevel(root)
##
## def save_changes(e1,e2,e3):
## global w,h,m
## w=e1.get()
## h=e2.get()
## m=e3.get()
## make_int()
## r.destroy()
##
## f=(" Courier ", 10)
## about="Minesweeper Settings"
## Label(r, font=f, text=about).grid(row=0)
## label1=Label(r, text="Width: ").grid(row=1)
## label2=Label(r, text="Height: ").grid(row=2)
## label3=Label(r, text="Mines: ").grid(row=3)
## e1=Entry(r, width=2)
## e1.insert(2, str(w))
## e1.grid(row=1,column=1)
## e2=Entry(r, width=2)
## e2.insert(2, str(h))
## e2.grid(row=2, column=1)
## e3=Entry(r, width=2)
## e3.insert(2, str(m))
## e3.grid(row=3, column=1)
##
## quit_button=Button(r, text='Quit', command=r.destroy).grid(row=4, column=0, sticky=W, pady=4)
## apply_button=Button(r, text='Apply', command=lambda:save_changes(e1,e2,e3)).grid(row=4, column=1, sticky=W, pady=4)
def line_loop(w,h):
seq=[]
c=0
for k in range(round(h/2)):
for j in range(0+c,w+c):
seq.append(j)
if j==(w*h)-1:
break
for i in range((w*2)-1+c,(w-1)+c,-1):
seq.append(i)
c+=(w*2)
c=0
for k in range(round(h/2)):
for j in range(w-1+c,-1+c,-1):
seq.append(j)
if j==(w*h)-1:
break
for i in range(w+c,(w*2)+c):
seq.append(i)
c+=(w*2)
return seq
##def make_int():
## global w,h,m
## w=int(w)
## h=int(h)
## m=int(m)
### --- MAIN --- ###
n=1
surround=[]
w=int(check_size(w))
h=int(check_size(h))
m=int(check_size(m))
geo=window_geometry(w,h)
root.geometry(geo)
mines=num_mines(m)
flags=len(mines)
frame0=Frame(root)
frame0.pack()
newgame=Button(frame0, text="New Game", bg="ivory3", command= newgame).pack(padx=5, pady=5, side=LEFT )
restart=Button(frame0, text="Restart", bg="ivory3", command= restart ).pack(padx=5, pady=5, side=LEFT)
#settingsb=Button(frame0, text="Settings", bg="ivory3", command= lambda: settings(w,h,m)).pack(padx=5, pady=5, side=RIGHT)
label=Label(root, text=flags, font=f, fg="blue")
label.pack()
button_creation()
middle=middle(w,h)
zeros=zeros_func()
line_loop=line_loop(w,h)
for i in line_loop:
adjacent_algorithm(i, "SET_MINE")
for i in line_loop:
adjacent_algorithm(i, "SET_BLOCK")
blocks=blocks_func()
for i in line_loop:
adjacent_algorithm(i, "SET_CHUNKS")
for i in line_loop:
adjacent_algorithm(i, "SET_CHUNKS")
root.mainloop()
### --- END --- ###