I am attempting to make Minesweeper in python using Tkinter. I have completed all of the initial logic but I am having trouble with the squares with zero surrounding bombs. The program is meant to open all of the surrounding squares when a square with zero surrounding bombs is clicked. The problem here is that it somehow creates an infinite loop. This may be due to the fact that I am calling the function click multiple times using a for loop but I am not sure if this is correct or how to fix it.
My code so far:
import tkinter as tk
from random import choices
from math import floor
##•
def openSurroundings(i):
trash = [i+1, i+8, i+9, i+10, i-1, i-8, i-9, i-10]
for a in trash:
if a<81:
click(floor(a/9), a-((a//9)*9))
def click(row, col):
text = numbers[row][col]
widget = buttons[row][col]
widget.grid_forget()
clickSurrounding = False
if text == 0:
text = ''
clickSurrounding = True
lab = tk.Label(window, text = text, height = 2, width = 5)
lab.grid(row = row, column = col)
if clickSurrounding == True:
openSurroundings((row*9)+col)
def placeBombs():
global widgets, bombs
numOfBombs = 10
widgets = list(range(1, (len(buttons)**2)+1))
bombs = choices(widgets, k = numOfBombs)
def findNumbers():
global numbers
numbers = []
lis_num = []
for i in widgets:
if i in bombs:
lis_num.append('•')
continue
else:
trash = [i+1, i+8, i+9, i+10, i-1, i-8, i-9, i-10]
num = 0
for a in trash:
if a > 0 and a in bombs:
num += 1
lis_num.append(num)
for i in range(0, len(lis_num), 9):
numbers.append(lis_num[i:i + 9])
window = tk.Tk()
window.title('Minesweeper')
sideLen = 9
row_index = 0
cell_index = 0
buttons = []
while row_index != sideLen:
button_row = []
while cell_index != sideLen:
button = tk.Button(window, width=5, height = 2, command=lambda row_index=row_index, cell_index=cell_index: click(row_index, cell_index))
button_row.append(button)
button.grid(row=row_index, column=cell_index)
cell_index += 1
buttons.append(button_row)
cell_index = 0
row_index += 1
placeBombs()
findNumbers()
Related
from tkinter import *
import random
master = Tk()
w = Canvas(master, width=400, height=400)
w.pack()
w.config(background = "white")
class gridTile:
def __init__(self,width,height,c1,c2,colour,val):
self.width = width
self.height = height
self.c1 = c1
self.c2 = c2
self.colour = colour
self.val = val
def draw(self):
w.create_rectangle(self.c1, self.c2, self.width + self.c1,
self.height + self.c2, fill = self.colour)
grid = [["a","b","c","d"],["1a","1b","1c","1d"],["2a","2b","2c","2d"],["3a","3b","3c","3d"]]
When I tested this in a separate environment it worked perfectly, when scaled up it doesn't work.
print(grid[(3)(3)])
grid_size = 4
count = 0
size = 60
for i in range(0,3):
print(i)
for j in range(0,3):
print(j)
count += 1
print (grid[[i][j]])
This range should be included within grid
grid[[i][j]] = gridTile(size,size,i*(size +10),j*(size + 10),"black",count)
def end():
sqry = random.randint(0,3)
sqrx = random.randint(0,3)
grid[[sqry][sqrx]].colour = "white"
for i in range(0,2):
x = random.randint(0,3)
y = random.randint(0,3)
mainloop()
Error:
<module>
grid[[i][j]] = gridTile(size,size,i*(size +10),j*(size + 10),"black",count)
IndexError: list index out of range
I’m on mobile but it seems like a 2D array. In order to access the value do grid[x][y] instead of tuples or arrays.
Please correct me if I’m misunderstanding something.
Let's look at grid[[i][j]]. The inside of that expression is [i][j]. If i = 2 and j = 3, for example, that expands to [2][3]. In other words, it creates a list [2] and then tries to get the item at index 3 from it.
That's not going to work. grid[i][j] is the correct syntax. But for real, don't do that for i in range(...) stuff. Like Matiiss said, you'd really want to write something like:
for sublist in grid:
for item in sublist:
print(item)
count += 1
Hello I am building a tkinter app and need to open photos within a function. Upon research I saw that you need to make the image = to a variable to keep track of it and use global. Despite doing these things my image still wont show up
can anyone help??
Here is my code
#when one of the catagory buttons is pressed this func is called opening a new window with
#a button for all images
def open_catagory(button_name):
fourth_window = Toplevel()
global fourth_pics
global fourthview
global CC
fourth_pics = (
"C:\\Users\\link\\OneDrive\\Desktop\\python stuff\\screenshot example\\Snapshots by catagory\\"+ str(button_name))
CC = [f for f in listdir(fourth_pics)]
print(CC)
fourthview = Image.open(
fourth_pics+"\\" + str(CC[-1]))
fourthveiw = fourthview.resize((800, 800), Image.ANTIALIAS)
fourthveiw = ImageTk.PhotoImage(fourthveiw)
fourth_window.config(height=1800, width=1800, bg="chocolate1")
fourthw_picture_box = Label(fourth_window, height=800, width=800,image = fourthveiw)
fourthw_picture_box.place(x=800, y=100)
count = 0
x = 1
y = 0
catagorypath = "C:\\Users\\link\\OneDrive\\Desktop\\python stuff\\screenshot example\\Snapshots by catagory\\" + str(button_name)
for g in listdir(catagorypath):
count += 1
for I in listdir(catagorypath ):
screenshot_snap = Button(fourth_window,text = str(I), bg = "chocolate3",activebackground = "white",padx= 80,pady =10)
screenshot_snap.grid(column = 4, row = int(x),rowspan = 5,columnspan = 5,padx = 50,pady =10)
x += 10
if y < count:
y += 1
I am currently making a hangman game and I have a global variable that indicates which part of the hangman to draw. The problem is that I need to change the value of this variable (drawRate) within a function as I will need it in a different function later on but python will not let me do this. Is there any way I can work around this problem?
import tkinter as tk
import turtle
import string
from functools import partial
from draw_hangman import drawHangman
word = 'hello'
shown_text = list('-'*len(word))
draw = drawHangman()
drawRate = 0
def whenPressed(button, text):
button.config(state = 'disabled')
ind = []
local_word = list(word)
for i in local_word :
if i == text:
trash = local_word.index(i)
ind.append(trash)
local_word.pop(trash)
local_word.insert(trash, '-')
if len(ind) != 0:
for i in ind:
shown_text.pop(i)
shown_text.insert(i, text)
lab.config(text = ''.join(shown_text))
for i in shown_text:
if i == '-':
trash = True
if trash != True:
print('You Won!')
else:
trash = draw[drawRate]
exec(trash)
drawRate+=1
root = tk.Tk()
t = turtle.Turtle()
alphabet = list(string.ascii_lowercase)
lab = tk.Label(root, text = '-'*len(word), font = (None, 15), width = 30)
lab.grid(row = 0, columnspan = 13)
for i in alphabet:
btn = tk.Button(root, text=i)
command = partial(whenPressed, btn, i)
btn.config(command=command)
row = (alphabet.index(i) // 13)+1
column = alphabet.index(i) % 13
btn.grid(row=row, column=column, sticky="news")
The variable draw is a list with the commands that draws the hangman figure:
draw = [
'''t.penup()
t.fd(200)
t.rt(90)
t.fd(200)''',
'''t.down()
t.lt(270)
t.fd(400)''',
'''t.rt(90)
t.fd(400)''',
'''t.rt(90)
t.fd(300)''',
'''t.rt(90)
t.fd(75)
t.dot(75)''',
't.fd(100)',
'''t.lt(90)
t.fd(60)''',
'''t.back(120)
t.fd(60)
t.rt(90)''',
'''t.fd(75)
t.lt(30)
t.fd(100)''',
'''t.back(100)
t.rt(60)
t.fd(100)''']
You have to declare this variable as global in the whenPressed() function like this:
def whenPressed(button, text):
global drawRate
...
I am a newbie, forgive me in advance if this is incorrect but can you not declare/bring in your global variable at the start of the function: global drawRate
def whenPressed(button, text):
global drawRate
button.config(state = 'disabled')
ind = []
local_word = list(word)
for i in local_word :
if i == text:
trash = local_word.index(i)
ind.append(trash)
local_word.pop(trash)
local_word.insert(trash, '-')
if len(ind) != 0:
for i in ind:
shown_text.pop(i)
shown_text.insert(i, text)
lab.config(text = ''.join(shown_text))
for i in shown_text:
if i == '-':
trash = True
if trash != True:
print('You Won!')
else:
trash = draw[drawRate]
exec(trash)
drawRate+=1
Try defining drawRate as global at the top of your whenPressed function
like
import turtle
import string
from functools import partial
from draw_hangman import drawHangman
word = 'hello'
shown_text = list('-'*len(word))
draw = drawHangman()
drawRate = 0
def whenPressed(button, text):
global drawRate
button.config(state = 'disabled')
ind = []
local_word = list(word)
for i in local_word :
if i == text:
trash = local_word.index(i)
ind.append(trash)
local_word.pop(trash)
local_word.insert(trash, '-')
if len(ind) != 0:
for i in ind:
shown_text.pop(i)
shown_text.insert(i, text)
lab.config(text = ''.join(shown_text))
for i in shown_text:
if i == '-':
trash = True
if trash != True:
print('You Won!')
else:
trash = draw[drawRate]
exec(trash)
drawRate+=1
root = tk.Tk()
t = turtle.Turtle()
alphabet = list(string.ascii_lowercase)
lab = tk.Label(root, text = '-'*len(word), font = (None, 15), width = 30)
lab.grid(row = 0, columnspan = 13)
for i in alphabet:
btn = tk.Button(root, text=i)
command = partial(whenPressed, btn, i)
btn.config(command=command)
row = (alphabet.index(i) // 13)+1
column = alphabet.index(i) % 13
btn.grid(row=row, column=column, sticky="news"```
I'm trying to change the button colour to black when clicked then change it back to white when clicked again. I'm trying to make Game Of Life for a school project.
I tried if statements but it doesn't change back to white, maybe I missed something simple. Here is the code:
from tkinter import *
class GUI(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
master.title("Window") #Window title
self.pack()
master.geometry("1280x720") #Window size
self.button={}#Dictionary for buttons
self.create_button()
def create_button(self):
indexList =[i for i in range(1000)]
self._button = Button(self, bg='white')
print(self._button.cget('bg'))
xPos = 0
yPos = 0
for index in indexList:
if(yPos == 40):
xPos = xPos + 20
yPos = 0
if(xPos == 10):
yPos = 8
self._button = Button(self, height=2, width=4, command = lambda
i = index: self.changecolour(i))
self.button[index] = self._button
self._button.grid(row=xPos, column =yPos)
yPos = yPos + 1
def changecolour(self,index):
aList = []
for i in range(1000):
aList.append([i,0])
for i in aList:
if index == i[0]:
if 0 == i[1]:
self.button[index].configure(bg = 'black')
i[1] = 1
else:
self.button[index].configure(bg = 'white')
i[1] = 0
root = Tk()
game_gui = GUI(master=root)
game_gui.mainloop()
As you can see it changes the button colour to black and it should change it back to white when clicked again, but it seems to just ignore the if statement.
I think this is the problem:
aList is not a global list
aList is created in changecolour() as a local list each time the subroutine is run
this means that when you do i[1] = 1 or i[1] = 0 it only changes the local list- aList. When the subroutine is run again, a new aList is created as a new local list.
to solve the problem define aList in the main program and make it a global list:
from tkinter import *
class GUI(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
master.title("Window") #Window title
self.pack()
master.geometry("1280x720") #Window size
self.button={}#Dictionary for buttons
self.create_button()
def create_button(self):
indexList =[i for i in range(1000)]
self._button = Button(self, bg='white')
print(self._button.cget('bg'))
xPos = 0
yPos = 0
for index in indexList:
if(yPos == 40):
xPos = xPos + 20
yPos = 0
if(xPos == 10):
yPos = 8
self._button = Button(self, height=2, width=4, command = lambda
i = index: self.changecolour(i))
self.button[index] = self._button
self._button.grid(row=xPos, column =yPos)
yPos = yPos + 1
def changecolour(self,index):
#aList IS NO LONGER CREATED HERE
for i in range(1000):
aList.append([i,0])
for i in aList:
if index == i[0]:
if 0 == i[1]:
self.button[index].configure(bg = 'black')
i[1] = 1
else:
self.button[index].configure(bg = 'white')
i[1] = 0
global aList #MAKE IT A GLOBAL LIST
aList = [] #CREATE THE EMPTY aList LIST
root = Tk()
game_gui = GUI(master=root)
game_gui.mainloop()
from tkinter import *
from random import *
from functools import partial
class Game:
def __init__(self):
self.root = Tk()
self.frame = Frame(width = 574, height = 574)
self.frame.grid(columnspan = 30, rowspan = 30)
self.minex = []
self.miney = []
self.clickx = 0
self.clicky = 0
blank = PhotoImage(file = 'C:\\Users\\PC\\Desktop\\Python Programs\\Minesweeper\\blank.gif')
for i in range(0,30):
for j in range(0,30):
button = Button(width = 15, height = 15, padx = 2, pady = 2, image = blank, command = partial(self.click, j, i))
button.grid(row = i, column = j)
self.mine_place()
self.root.mainloop()
def mine_place(self):
for i in range(0,15):
self.minex.append(randint(1,30))
self.miney.append(randint(1,30))
def click(self, j, i):
miss = PhotoImage(file = 'C:\\Users\\PC\\Desktop\\Python Programs\\Minesweeper\\miss.gif')
hit = PhotoImage(file = 'C:\\Users\\PC\\Desktop\\Python Programs\\Minesweeper\\hit.gif')
for k in range(0, len(self.minex)):
if j + 1 == self.minex[k] and i + 1 == self.miney[k]:
button = Button(image = hit)
button.grid(row = i, column = j)
else:
button = Button(image = miss)
button.grid(row = i, column = j)
app = Game()
In self.click, when I wish to create a button with this image I am given a blank image. If I create a button in init, the image comes out just fine. What is wrong?..............................................................
It looks like you're images are getting garbage collected you need to save a reference to the images after using PhotoImage.
ie - you create the image blank so save a reference as self.blank= blank and use image = self.hit