0
votes

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()

   
Do some research on the after method provided by tkinter. There must be hundreds of questions on this site related to timers, delays, clocks, etc. that are largely all answered by using after. - Bryan Oakley
This seems useful. Thanks. I' ve come across after_idle which did not work when I tried it...that is why I excluded this posibility - Flavius Miron
Please trim your code to make it easier to find your problem. Follow these guidelines to create a minimal reproducible example. - Community