【问题标题】:TicTacToe Tkinter GUI keeps crashingTicTacToe Tkinter GUI 不断崩溃
【发布时间】:2020-12-27 14:47:26
【问题描述】:

我正在尝试使用 Tkinter 制作一个简单的井字游戏,但我无法真正对其进行测试,因为应用程序不断崩溃。我不能比第二轮更进一步。谁能告诉我为什么它总是崩溃?实现了after()方法后好像好了一点,但是还是不能正常运行。

这是我的代码:

import tkinter as tk
from tkinter import messagebox
from random import randrange


# click function
def choose(event):
    global game_over
    if not game_over:
        if event.widget["state"] == "normal":
            event.widget.configure(text="O", disabledforeground="#0000ff", state="disabled")
            # check for winner
            window.after(1000, check)
            # let computer make its move
            if not game_over:
                window.after(1000, machine_move)
                # check again
                window.after(1000, check)
        elif event.widget["state"] == "disabled":
            messagebox.showerror("Field taken", "Please choose a different field")


# define machine move
def machine_move():
    global taken
    pick = randrange(1, 9)
    taken = True
    while taken:
        if button_dict[pick-1].cget("state") == "normal":
            button_dict[pick-1].configure(text="X", disabledforeground="#ff0000", state="disabled")
            taken = False


# check for winner function
def check():
    global game_over
    global inputs
    inputs = []
    for key in button_dict.keys():
        inputs.append(button_dict[key].cget("text"))
    # line win
    if inputs[0] == "X" and inputs[1] == "X" and inputs[2] == "X" \
    or inputs[3] == "X" and inputs[4] == "X" and inputs[5] == "X" \
    or inputs[6] == "X" and inputs[7] == "X" and inputs[8] == "X":
        messagebox.showinfo("Game over", "Line win by machine")
        game_over = True
    elif inputs[0] == "O" and inputs[1] == "O" and inputs[2] == "O" \
    or inputs[3] == "O" and inputs[4] == "O" and inputs[5] == "O" \
    or inputs[6] == "O" and inputs[7] == "O" and inputs[8] == "O":
        messagebox.showinfo("Game over", "Line win by you")
        game_over = True
    # row win
    elif inputs[0] == "X" and inputs[3] == "X" and inputs[6] == "X" \
    or inputs[1] == "X" and inputs[4] == "X" and inputs[7] == "X" \
    or inputs[2] == "X" and inputs[5] == "X" and inputs[8] == "X":
        messagebox.showinfo("Game over", "Row win by machine")
        game_over = True
    elif inputs[0] == "O" and inputs[3] == "O" and inputs[6] == "O" \
    or inputs[1] == "O" and inputs[4] == "O" and inputs[7] == "O" \
    or inputs[2] == "O" and inputs[5] == "O" and inputs[8] == "O":
        messagebox.showinfo("Game over", "Row win by you")
        game_over = True
    # check for diagonal win
    elif inputs[0] == "X" and inputs[4] == "X" and inputs[8] == "X" \
    or inputs[2] == "X" and inputs[4] == "X" and inputs[6] == "X":
        messagebox.showinfo("Game over", "Diagonal win by machine")
        game_over = True
    elif inputs[0] == "O" and inputs[4] == "O" and inputs[8] == "O" \
    or inputs[2] == "O" and inputs[4] == "O" and inputs[6] == "O":
        messagebox.showinfo("Game over", "Diagonal win by machine")
        game_over = True


# create window
window = tk.Tk()
window.title("TicTacToe")
window.geometry("450x480")


# create buttons

button_dict = {}
for i in range(9):
    new_button = tk.Button(window, text=" ", width=3, font=30)
    new_button.grid(column=i // 3, row=i % 3, ipadx=50, ipady=50)
    new_button.bind("<Button-1>", choose)
    button_dict[i] = new_button


# start game
game_over = False
button_dict[4].configure(text="X", disabledforeground="#ff0000", state="disabled")
window.mainloop()

【问题讨论】:

  • machine_move 函数的 while 循环体中,变量 pick 永远不会从其初始状态改变。所以,如果随机选择的按钮碰巧被禁用,你永远不会跳出循环,程序就会挂起。

标签: python user-interface tkinter crash tic-tac-toe


【解决方案1】:

正如@Paul M 在 cmets 中所说,如果 machine_move 函数中的 pick 变量恰好是已禁用的按钮,则其值将保持不变并且 while 循环无限期地运行导致你的程序挂了。要克服这个问题,您可以尝试以下方法(这是解决此问题的众多解决方案之一)

def machine_move():
    available_buttons=[button_dict[i] for i in range(len(button_dict)) if button_dict[i].cget("state") == "normal"]
    pick = choice(available_buttons)
    pick.configure(text="X", disabledforeground="#ff0000", state="disabled")

所以,基本上available_buttons 列表包含尚未禁用的按钮,变量pick 是从该列表中随机选择(使用random.choice()),然后进行相应配置。

更新

我还注意到您正在使用after 方法调用check(),如果在调用检查之前进行另一次移动,这可能会导致严重延迟决定获胜者,有时会导致多个获胜者,以克服这个你可以试试这个(同样,这是解决这个问题的众多解决方案之一)

def choose(event):
    global game_over
    if not game_over:
        if event.widget["state"] == "normal":
            event.widget.configure(text="O", disabledforeground="#0000ff", state="disabled")
            # check for winner
            check()
            # let computer make its move
            if not game_over:
                window.after(1000, machine_move)
        elif event.widget["state"] == "disabled":
            messagebox.showerror("Field taken", "Please choose a different field")


# define machine move
def machine_move():
    available_buttons=[button_dict[i] for i in range(len(button_dict)) if button_dict[i].cget("state") == "normal"]
    pick = choice(available_buttons)
    pick.configure(text="X", disabledforeground="#ff0000", state="disabled")
    check()

在玩家或机器移动后立即致电check()

【讨论】:

    猜你喜欢
    • 2015-02-02
    • 2016-12-18
    • 1970-01-01
    • 2023-01-31
    • 2014-01-27
    • 2018-01-10
    • 1970-01-01
    • 2021-08-16
    • 2012-09-03
    相关资源
    最近更新 更多