I was making a tic-tac-toe game and I wanted to simulate that the computer is "thinking" ,so I thought about introducing a delay with time.sleep() . However, giving how my event reacting to any of the 9 squares clicking is designed, I couldn't interrupt the callback and the delay takes place after the whole body is executed:
def on_button_click_event(event):
if current_board.checkAvailable(event.widget):
current_board.user_move(event)
time.sleep(1)
current_board.checkForVictory()
if not current_board.end:
current_board.computer_move()
current_board.checkForVictory()
else:
info.config(text="Already occupied!",font="Comic 14")
Now this makes the program wait 1 sec ... then executes both user_move and computer_move at the same time.I wasnted to execute the user_move -> wait 1 sec or so -> then execute computer_move.
I tried to put it inside the user_move callback or computer_move callback but the result is the same.
From what I found out online, somehow using time.delay() delays the execution of the thread as a whole and that might be the problem.
So I was looking forward to know if there is other function/method that does what I am asking or if there could be a better approach to somehow separate the events. (I thought about this one but considering what I have learned so far including the computer_move after a user_move in the event handler was the best choice I came with ).
I will leave my full program's code here:
import tkinter as tk
from tkinter import messagebox
import random
import time
from tkinter import simpledialog
from numpy import imag
class board:
def __init__(self):
self.__available=[i for i in range(1,10)]
self.__matches=
{frame1:1,frame2:2,frame3:3,frame4:4,frame5:5,frame6:6,frame7:7,frame8:8,frame9:9}
self.__matches_reversed=
{1:frame1,2:frame2,3:frame3,4:frame4,5:frame5,6:frame6,7:frame7,8:frame8,9:frame9}
self.__associations=
{1:None,2:None,3:None,4:None,5:None,6:None,7:None,8:None,9:None}
global coputer_begins
self.end=False
if computer_begins:
self.computer_move()
def lenAvailable(self):
return len(self.__available)
def checkAvailable(self,widget):
return self.__matches[widget] in self.__available
def checkForVictory(self):
info.config(text="The game continues!",font="Comic 14")
associacions=list(self.__associations.values())
print(associacions)
o=['o','o','o']
x=['x','x','x']
won=None
for i in range(0,9,3):
if associacions[i:i+3] == o:
won=False
for j in range(i,i+3):
self.__matches_reversed[j+1].config(image=object_photo_ored)
break
elif associacions[i:i+3] == x:
won=True
for j in range(i,i+3):
self.__matches_reversed[j+1].config(image=object_photo_xred)
break
if won == None:
for i in range(3):
if associacions[i:i+9:3] == o:
for j in range(i,i+9,3):
self.__matches_reversed[j+1].config(image=object_photo_ored)
won=False
break
elif associacions[i:i+9:3] == x:
for j in range(i,i+9,3):
self.__matches_reversed[j+1].config(image=object_photo_xred)
won=True
break
if won == None:
if associacions[0:9:4] == o:
for j in range(0,9,4):
self.__matches_reversed[j+1].config(image=object_photo_ored)
won=False
elif associacions[0:9:4] == x:
for j in range(0,9,4):
self.__matches_reversed[j+1].config(image=object_photo_xred)
won=True
if won == None:
prov=[]+[associacions[2]]+[associacions[4]]+[associacions[6]]
if prov == o:
for j in prov:
self.__matches_reversed[j+1].config(image=object_photo_ored)
won=False
elif prov == x:
for j in prov:
self.__matches_reversed[j+1].config(image=object_photo_xred)
won=True
if won == True:
self.end=True
unbindall()
info.config(text="User won!",font="Comic 14")
elif won == False:
self.end=True
unbindall()
info.config(text="Computer won!",font="Comic 14")
elif current_board.lenAvailable():
info.config(text="Continue!",font="Comic 14")
else:
self.end=True
unbindall()
info.config(text="Tie!",font="Comic 14")
def computer_move(self):
move = random.choice(self.__available)
#move = simpledialog.askinteger("s","s")
self.__matches_reversed[move].config(imag = object_photo_o)
self.__available.remove(move)
self.__associations[move]="o"
print(self.__associations)
print(self.__available)
def user_move(self,event):
move = self.__matches[event.widget]
print(move)
print(type(move))
event.widget.config(image=object_photo_x)
print(self.__available)
self.__available.remove(move)
self.__associations[move] = "x"
print(self.__associations)
print(self.__available)
time.sleep(1)
def unbindall():
frame1.unbind("<Button-1>")
frame2.unbind("<Button-1>")
frame3.unbind("<Button-1>")
frame4.unbind("<Button-1>")
frame5.unbind("<Button-1>")
frame6.unbind("<Button-1>")
frame7.unbind("<Button-1>")
frame8.unbind("<Button-1>")
frame9.unbind("<Button-1>")
def on_button_click_event(event):
if current_board.checkAvailable(event.widget):
current_board.user_move(event)
time.sleep(1)
current_board.checkForVictory()
if not current_board.end:
current_board.computer_move()
current_board.checkForVictory()
else:
info.config(text="Already occupied!",font="Comic 14")
main_window = tk.Tk()
main_window.geometry("460x650")
main_window.config(bg="#CCCCCC")
main_window.title("X si O")
#THIS PART IS WHERE I CREATED PHOTOS AND LABELS
object_photo_x = tk.PhotoImage(file="C:\\Users\\Flavius\\Documents\\Visual Studio 2019\\ticandtoe\\x.png")
object_photo_o = tk.PhotoImage(file="C:\\Users\\Flavius\\Documents\\Visual Studio 2019\\ticandtoe\\o.png")
object_photo_xred = tk.PhotoImage(file="C:\\Users\\Flavius\\Documents\\Visual Studio 2019\\ticandtoe\\xred.png")
object_photo_ored = tk.PhotoImage(file="C:\\Users\\Flavius\\Documents\\Visual Studio 2019\\ticandtoe\\ored.png")
frame1=tk.Label(main_window, bg="#FFFFFF")
frame1.place(x=50,y=250 ,height=110, width=110)
i1=frame1.bind("<Button-1>",on_button_click_event)
frame2=tk.Label(main_window, bg="#FFFFFF")
frame2.place(x=175,y=250, height=110, width=110)
i2=frame2.bind("<Button-1>",on_button_click_event)
frame3=tk.Label(main_window, bg="#FFFFFF")
frame3.place(x=300,y=250, height=110, width=110)
i3=frame3.bind("<Button-1>",on_button_click_event)
frame4=tk.Label(main_window, bg="#FFFFFF")
frame4.place(x=50,y=375, height=110, width=110)
i4=frame4.bind("<Button-1>",on_button_click_event)
frame5=tk.Label(main_window, bg="#FFFFFF")
frame5.place(x=175,y=375, height=110, width=110)
i5=frame5.bind("<Button-1>",on_button_click_event)
frame6=tk.Label(main_window, bg="#FFFFFF")
frame6.place(x=300,y=375,height=110, width=110)
i6=frame6.bind("<Button-1>",on_button_click_event)
frame7=tk.Label(main_window, bg="#FFFFFF")
frame7.place(x=50,y=500, height=110, width=110)
i7=frame7.bind("<Button-1>",on_button_click_event)
frame8=tk.Label(main_window, bg="#FFFFFF")
frame8.place(x=175,y=500, height=110, width=110)
i8=frame8.bind("<Button-1>",on_button_click_event)
frame9=tk.Label(main_window, bg="#FFFFFF")
frame9.place(x=300,y=500, height=110, width=110)
i9=frame9.bind("<Button-1>",on_button_click_event)
info=tk.Label(main_window, bg ="#BBBBBB",text="Player plays with X and computer with O!",font="Comic 14")
info.place(x=50,y=40,height=160,width=360) #x=50,y=40
coputer_begins=True
current_board=board()
main_window.mainloop()
aftermethod provided by tkinter. There must be hundreds of questions on this site related to timers, delays, clocks, etc. that are largely all answered by usingafter. - Bryan Oakley