Написал игру крестики-нолики, графика кнопочная на tkinter. Все работает хорошо, кроме одного места. Дело в том, что первые ходы у меня заложены, дальше, между 2 и 3 ходом, если начинает игру компьютер, производятся вычисления. В этот момент кнопка tkinter, на которую нажимали, делая второй ход, виснет, пока вычисления не будут произведены. Я так понимаю, что это происходит от того, что нажатие-отжатие кнопки занимает около 0.1 секунды, а вычисления начинаются намного раньше, поэтому копал в сторону функций, делающих паузу, sleep, например, потом в сторону блокировок, но пока не помогает. Привожу здесь свой код, приму критику по поводу грязноты и избыточности. Нужное место - между 166 строкой создания кнопки и 167ой начала вычислений, отмечено множественными восклицательными знаками в комментариях. Подскажите, пожалуйста, где искать решение.
from random import choice as random import sys from threading import Timer import time from tkinter import * this_game_code='' def start(): global startg, startgfr startg=Tk() startg.resizable(height=FALSE, width=FALSE) startgfr=Frame(startg) startgfr2=Frame(startg) startg.title("Oleg x_and_zero") startg.minsize(100,20) ws=startg.winfo_screenwidth() hs=startg.winfo_screenheight() x=(ws/2)-105 y=(hs/2)-66 startg.geometry('%dx%d+%d+%d' %(210,70,x,y)) Label(startgfr, text="Who will begin? ").grid(row=0, column=1, columnspan=2) Button(startgfr, text="Computer", command=lambda:beginner("1")).grid(row=1, column=1) Button(startgfr, text="Player", command=lambda:beginner("2")).grid(row=1, column=2) startgfr.pack(anchor=CENTER) startgfr2.pack(anchor=CENTER) startg.mainloop() def result(code): number_of_lettercode = 0 number_of_symbol = 0 player1 = [None]*5 player2 = [None]*5 result = 0 while number_of_lettercode<len(code): player1[number_of_symbol] = code[number_of_lettercode] number_of_symbol=number_of_symbol+1 number_of_lettercode=number_of_lettercode+2 number_of_lettercode = 1 number_of_symbol = 0 while number_of_lettercode<len(code): player2[number_of_symbol] = code[number_of_lettercode] number_of_symbol=number_of_symbol+1 number_of_lettercode=number_of_lettercode+2 if {'1','4','7'}.difference(player1) == set(): result = 1 if {'2','5','8'}.difference(player1) == set(): result = 1 if {'3','6','9'}.difference(player1) == set(): result = 1 if {'1','2','3'}.difference(player1) == set(): result = 1 if {'4','5','6'}.difference(player1) == set(): result = 1 if {'7','8','9'}.difference(player1) == set(): result = 1 if {'1','5','9'}.difference(player1) == set(): result = 1 if {'3','5','7'}.difference(player1) == set(): result = 1 if {'1','4','7'}.difference(player2) == set(): result = -1 if {'2','5','8'}.difference(player2) == set(): result = -1 if {'3','6','9'}.difference(player2) == set(): result = -1 if {'1','2','3'}.difference(player2) == set(): result = -1 if {'4','5','6'}.difference(player2) == set(): result = -1 if {'7','8','9'}.difference(player2) == set(): result = -1 if {'1','5','9'}.difference(player2) == set(): result = -1 if {'3','5','7'}.difference(player2) == set(): result = -1 return(result) def no_same_letter(code): count1 = 0 while count1 < len(code): count2 = count1 + 1 while count2 < len(code): if code[count1] == code[count2]: return('no') count2 = count2 + 1 count1 = count1 + 1 return('yes') def make_tree(code): global element, number_of_element_in_spisok Spisok_dereva[1] = int(code) Slovar_dereva[str(code)] = 0 while True: if Spisok_dereva[element] != None: if Slovar_dereva[str(Spisok_dereva[element])] == 0: may_be_next_letter = 1 while may_be_next_letter < 10: if no_same_letter(str(Spisok_dereva[element])+str(may_be_next_letter)) == 'yes': Spisok_dereva[number_of_element_in_spisok] = int(str(Spisok_dereva[element])+str(may_be_next_letter)) Slovar_dereva[(str(Spisok_dereva[element])+str(may_be_next_letter))] = result(str(Spisok_dereva[element])+str(may_be_next_letter)) number_of_element_in_spisok = number_of_element_in_spisok + 1 may_be_next_letter = may_be_next_letter + 1 element = element + 1 else: break while True: if Spisok_dereva[-1] == None: Spisok_dereva.remove(None) else: break #print(Spisok_dereva[-100:]) #print('done') length_of_hod = 9 def player1_choice(length_of_hod): global number_of_element_in_spisok while len(str(Spisok_dereva[number_of_element_in_spisok-1])) == length_of_hod: main_vetka = str(Spisok_dereva[number_of_element_in_spisok-1])[:-1] bestresult = Slovar_dereva[str(Spisok_dereva[number_of_element_in_spisok-1])] while str(Spisok_dereva[number_of_element_in_spisok-1])[:-1] == main_vetka: if Slovar_dereva[str(Spisok_dereva[number_of_element_in_spisok-1])] > bestresult: bestresult = Slovar_dereva[str(Spisok_dereva[number_of_element_in_spisok-1])] Slovar_dereva[main_vetka] = bestresult number_of_element_in_spisok = number_of_element_in_spisok - 1 def player2_choice(length_of_hod): global number_of_element_in_spisok while len(str(Spisok_dereva[number_of_element_in_spisok-1])) == length_of_hod: main_vetka = str(Spisok_dereva[number_of_element_in_spisok-1])[:-1] bestresult = Slovar_dereva[str(Spisok_dereva[number_of_element_in_spisok-1])] while str(Spisok_dereva[number_of_element_in_spisok-1])[:-1] == main_vetka: if Slovar_dereva[str(Spisok_dereva[number_of_element_in_spisok-1])] < bestresult: bestresult = Slovar_dereva[str(Spisok_dereva[number_of_element_in_spisok-1])] Slovar_dereva[main_vetka] = bestresult number_of_element_in_spisok = number_of_element_in_spisok - 1 def testfunction(code): may_be_next_letter = 1 while True: if no_same_letter(str(code)+str(may_be_next_letter)) == 'yes': if Slovar_dereva[str(code)+str(may_be_next_letter)] == Slovar_dereva[str(code)]: code = str(code)+str(may_be_next_letter) break may_be_next_letter = may_be_next_letter + 1 return(code) #who_first = input('Who will begin? Press 1 for computer or 2 for player ') def game(player_motion): global this_game_code, x, y, computer_first_motion, who_first if who_first == '1': # Computer goes first if len(this_game_code)<1: computer_first_motion = random('1379') this_game_code = computer_first_motion Button(rootf, text=computer_sym, height=2, width=5).grid(row=int((int(computer_first_motion)-0.1)/3),column=int((int(computer_first_motion)-0.1)%3)) root.mainloop() elif len(this_game_code) == 1: this_game_code = this_game_code+str(player_motion) Button(rootf, text=player_sym, height=2, width=5).grid(row=int((int(player_motion)-0.1)/3),column=int((int(player_motion)-0.1)%3)) #!!!!!!!!!!!!!!!!!! make_tree(this_game_code)#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! player1_choice(9) player2_choice(8) player1_choice(7) player2_choice(6) player1_choice(5) player2_choice(4) player1_choice(3) player2_choice(2) this_game_code = testfunction(this_game_code) Button(rootf, text=computer_sym, height=2, width=5).grid(row=int((int(this_game_code[-1])-0.1)/3),column=int((int(this_game_code[-1])-0.1)%3)) elif len(this_game_code) < 7: Button(rootf, text=player_sym, height=2, width=5).grid(row=int((int(player_motion)-0.1)/3),column=int((int(player_motion)-0.1)%3)) this_game_code = testfunction(str(this_game_code)+str(player_motion)) Button(rootf, text=computer_sym, height=2, width=5).grid(row=int((int(this_game_code[-1])-0.1)/3),column=int((int(this_game_code[-1])-0.1)%3)) if result(this_game_code) != 0: root.geometry('%dx%d+%d+%d' %(210,222,x,y)) Label(rootf, text=" Computer win! ").grid(row=3, column=0, columnspan=3) Label(rootf, text=" Play again or quit? ").grid(row=4, column=0, columnspan=3) Button(rootf, text="Again", height=2, width=5, command=lambda:again()).grid(row=5,column=0) Button(rootf, text="Quit", height=2, width=5, command=lambda:root.withdraw()).grid(row=5, column=2) elif len(this_game_code) == 7: Button(rootf, text=player_sym, height=2, width=5).grid(row=int((int(player_motion)-0.1)/3),column=int((int(player_motion)-0.1)%3)) this_game_code = testfunction(str(this_game_code)+str(player_motion)) Button(rootf, text=computer_sym, height=2, width=5).grid(row=int((int(this_game_code[-1])-0.1)/3),column=int((int(this_game_code[-1])-0.1)%3)) if result(this_game_code) == 0: Label(rootf, text=" Draw! ").grid(row=3, column=0, columnspan=3) else: Label(rootf, text=" Computer win! ").grid(row=3, column=0, columnspan=3) root.geometry('%dx%d+%d+%d' %(210,222,x,y)) Label(rootf, text=" Play again or quit? ").grid(row=4, column=0, columnspan=3) Button(rootf, text="Again", height=2, width=5, command=lambda:again()).grid(row=5,column=0) Button(rootf, text="Quit", height=2, width=5, command=lambda:root.withdraw()).grid(row=5, column=2) else: # Player goes first #player_motion = input('your motion, please ') if len(this_game_code)<2: #Beginning of the game if player_motion == '5': second_motion = random('1379') else: second_motion = '5' this_game_code = str(player_motion)+str(second_motion) Button(rootf, text=player_sym, height=2, width=5).grid(row=int((int(player_motion)-0.1)/3),column=int((int(player_motion)-0.1)%3)) #print(this_game_code) Button(rootf, text=computer_sym, height=2, width=5).grid(row=int((int(second_motion)-0.1)/3),column=int((int(second_motion)-0.1)%3)) elif len(this_game_code) == 2: this_game_code = this_game_code + str(player_motion) Button(rootf, text=player_sym, height=2, width=5).grid(row=int((int(player_motion)-0.1)/3),column=int((int(player_motion)-0.1)%3)) make_tree(this_game_code) player1_choice(9) player2_choice(8) player1_choice(7) player2_choice(6) player1_choice(5) player2_choice(4) player1_choice(3) player2_choice(2) this_game_code = testfunction(this_game_code) Button(rootf, text=computer_sym, height=2, width=5).grid(row=int((int(this_game_code[-1])-0.1)/3),column=int((int(this_game_code[-1])-0.1)%3)) elif len(this_game_code) <8: this_game_code = testfunction(str(this_game_code)+str(player_motion)) Button(rootf, text=player_sym, height=2, width=5).grid(row=int((int(player_motion)-0.1)/3),column=int((int(player_motion)-0.1)%3)) if result(this_game_code) == 0: Button(rootf, text=computer_sym, height=2, width=5).grid(row=int((int(this_game_code[-1])-0.1)/3),column=int((int(this_game_code[-1])-0.1)%3)) else: Button(rootf, text=computer_sym, height=2, width=5).grid(row=int((int(this_game_code[-1])-0.1)/3),column=int((int(this_game_code[-1])-0.1)%3)) root.geometry('%dx%d+%d+%d' %(210,222,x,y)) Label(rootf, text=" Computer win! ").grid(row=3, column=0, columnspan=3) Label(rootf, text=" Play again or quit? ").grid(row=4, column=0, columnspan=3) Button(rootf, text="Again", height=2, width=5, command=lambda:again()).grid(row=5,column=0) Button(rootf, text="Quit", height=2, width=5, command=lambda:root.withdraw()).grid(row=5, column=2) elif len(this_game_code) == 8: this_game_code = this_game_code + str(player_motion) Button(rootf, text=player_sym, height=2, width=5).grid(row=int((int(player_motion)-0.1)/3),column=int((int(player_motion)-0.1)%3)) if result(this_game_code) == 0: Label(rootf, text=" Draw! ").grid(row=3, column=0, columnspan=3) else: Label(rootf, text=" Computer win! ").grid(row=3, column=0, columnspan=3) root.geometry('%dx%d+%d+%d' %(210,222,x,y)) Label(rootf, text=" Play again or quit? ").grid(row=4, column=0, columnspan=3) Button(rootf, text="Again", height=2, width=5, command=lambda:again()).grid(row=5,column=0) Button(rootf, text="Quit", height=2, width=5, command=lambda:root.withdraw()).grid(row=5, column=2) def beginner(who): global who_first, startg, startgfr who_first = who startg.withdraw() startg=Tk() startg.resizable(height=FALSE, width=FALSE) startgfr=Frame(startg) startgfr2=Frame(startg) startg.title("Oleg x_and_zero") startg.minsize(100,20) ws=startg.winfo_screenwidth() hs=startg.winfo_screenheight() x=(ws/2)-105 y=(hs/2)-66 startg.geometry('%dx%d+%d+%d' %(210,70,x,y)) Label(startgfr, text="Choose your symbol ").grid(row=0, column=1, columnspan=2) Button(startgfr, text="X", command=lambda:choosesym("X")).grid(row=1, column=1) Button(startgfr, text="O", command=lambda:choosesym("O")).grid(row=1, column=2) startgfr.pack(anchor=CENTER) startgfr2.pack(anchor=CENTER) startg.mainloop()# main() def choosesym(sym): global player_sym, computer_sym if sym == 'X': player_sym = 'X' computer_sym = 'O' else: player_sym = 'O' computer_sym = 'X' main() def main(): global b1 , b2 , b3 , b4 ,b5 , b6, b7 , b8 , b9, sys , sym , root, rootf, x, y global Slovar_dereva, Spisok_dereva, element, number_of_element_in_spisok, player_sym, computer_sym Slovar_dereva = {} Spisok_dereva = [0]+[None]*9000 element = 1 number_of_element_in_spisok = 2 startg.withdraw() root=Tk() root.minsize(120,140) root.resizable(height=False, width=False) root.title("Oleg x_and_zero") rootf=Frame(root) ws=root.winfo_screenwidth() hs=root.winfo_screenheight() x=(ws/2)-105 y=(hs/2)-66 root.geometry('%dx%d+%d+%d' %(210,132,x,y)) b1=Button(rootf, text="", height=2, width=5, command=lambda:game('1')) b2=Button(rootf, text="", height=2, width=5, command=lambda:game('2')) b3=Button(rootf, text="", height=2, width=5, command=lambda:game('3')) b4=Button(rootf, text="", height=2, width=5, command=lambda:game('4')) b5=Button(rootf, text="", height=2, width=5, command=lambda:game('5')) b6=Button(rootf, text="", height=2, width=5, command=lambda:game('6')) b7=Button(rootf, text="", height=2, width=5, command=lambda:game('7')) b8=Button(rootf, text="", height=2, width=5, command=lambda:game('8')) b9=Button(rootf, text="", height=2, width=5, command=lambda:game('9')) b1.grid(row=0,column=0) b2.grid(row=0,column=1) b3.grid(row=0,column=2) b4.grid(row=1,column=0) b5.grid(row=1,column=1) b6.grid(row=1,column=2) b7.grid(row=2,column=0) b8.grid(row=2,column=1) b9.grid(row=2,column=2) rootf.pack(anchor=CENTER) if who_first == '1': game('') root.mainloop() def again(): global this_game_code, Slovar_dereva, Spisok_dereva, element, number_of_element_in_spisok root.withdraw() Slovar_dereva = {} Spisok_dereva = [0]+[None]*9000 this_game_code = '' element = 1 number_of_element_in_spisok = 2 start() start()
Этого делать не стоит, код приведен только для того, чтоб можно было запустить игру и посмотреть, как она работает, а она работает, только подвисает на несколько секунд в одном месте! Может, не совсем понятно пишу, но, если запустить код, станет понятнее. Несколько операций совершенно точно есть в одном цикле в функции, вычисляющей дерево ходов make_tree(), но это необходимо, и, даже если реализовать в отдельных циклах отдельные операции, вычислительная нагрузка в 5000 комбинаций, с вычислением результата, просчетом оценок ветвей, все равно будет такой же.