Проблемы с Tkinter и Tic-Tac-Toe

1

Я писал игру Tic-Tac-Toe, используя Tkinter. Когда один пользователь выигрывает, появляется окно Toplevel с кнопкой "Перезагрузить", которое должно перезапустить программу, но я получаю неожиданную ошибку, когда нажимаю на нее. Я знаю, что моя функция проверки победителя глупа, но я мог бы написать лучшую с моим текущим уровнем знаний. Сообщение об ошибке:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\Eldiiar Raiymkulov\AppData\Local\Programs\Python\Python36-32\lib\tkinter\__init__.py", line 1699, in __call__
    return self.func(*args)
  File "C:\Users\Eldiiar Raiymkulov\Desktop\xo2.py", line 62, in <lambda>
    command=lambda x=x, y=y: clicked(y, x)))
  File "C:\Users\Eldiiar Raiymkulov\Desktop\xo2.py", line 15, in clicked
    isWinner(char)
  File "C:\Users\Eldiiar Raiymkulov\Desktop\xo2.py", line 46, in isWinner
    topMessage(char)
  File "C:\Users\Eldiiar Raiymkulov\Desktop\xo2.py", line 30, in topMessage
    topButton = Button(top, text="Restart", command=restart(root))
NameError: name 'root' is not defined

И вот код:

from tkinter import *

turn = True
btns = None
def clicked(y, x):
    global turn, btns
    char = ""
    if turn:
        char = "X"
    else:
        char = "O"

    btns[y][x].config(text=char,
                      state=DISABLED)
    isWinner(char)
    turn = not turn

def restart(root):
    global turn
    turn = True
    root.destroy()
    main()
def topMessage(char):
    global root
    top = Toplevel()
    top.title("Congratulations!")
    topText = Label(top, text=f"{char} is a winner!")
    topButton = Button(top, text="Restart", command=restart(root))
    topText.grid(row=0)
    topButton.grid(row=1)
def isWinner(char):
    global root
        #horizontal
    if (((btns[1][1].cget("text") == char) and (btns[1][2].cget("text") == char) and (btns[1][3].cget("text") == char)) or
    ((btns[2][1].cget("text") == char) and (btns[2][2].cget("text") == char) and (btns[2][3].cget("text") == char)) or  
    ((btns[3][1].cget("text") == char) and (btns[3][2].cget("text") == char) and (btns[3][3].cget("text") == char)) or  
        #vertical
    ((btns[1][1].cget("text") == char) and (btns[2][1].cget("text") == char) and (btns[3][1].cget("text") == char)) or
    ((btns[1][2].cget("text") == char) and (btns[2][2].cget("text") == char) and (btns[3][2].cget("text") == char)) or
    ((btns[1][3].cget("text") == char) and (btns[2][3].cget("text") == char) and (btns[3][3].cget("text") == char)) or
        #diagonal
    ((btns[1][1].cget("text") == char) and (btns[2][2].cget("text") == char) and (btns[3][3].cget("text") == char)) or
    ((btns[1][3].cget("text") == char) and (btns[2][2].cget("text") == char) and (btns[3][1].cget("text") == char))):
        topMessage(char)


def main():
    global btns
    root = Tk()
    root.title("X and O of Daniar")
    root.resizable(False, False)
    btns = [None]
    for y in range(1, 4):
        row = [None]
        for x in range(1, 4):
            row.append(Button(root,
                              width=5,
                              height=3,
                              font="time 12 bold",
                              command=lambda x=x, y=y: clicked(y, x)))
            row[x].grid(row=y, column=x)
        btns.append(row)

    Button(root,
           text="Restart",
           width=5,
           command=lambda: restart(root)).grid(row=4, column=2)

    root.mainloop()

main()

Кроме того, если у вас есть более разумные предложения по функциям isWinner, не могли бы вы поделиться ими со мной?

Теги:
tkinter

1 ответ

0

Это должно исправить вашу проблему.

Вам нужно было определить переменную вне функций, чтобы использовать ее с глобальным, и чтобы main() использовал эту переменную. Также, если вы вызываете какую-либо функцию в команде и передаете в функцию переменную, всегда используйте лямбду.

from tkinter import *

turn = True
btns = None
root = None


def clicked(y, x):
    global turn, btns
    char = ""
    if turn:
        char = "X"
    else:
        char = "O"

    btns[y][x].config(text=char,
                      state=DISABLED)
    isWinner(char)
    turn = not turn


def restart(root):
    global turn
    turn = True
    root.destroy()
    main()


def topMessage(char):
    global root
    top = Toplevel()
    top.title("Congratulations!")
    topText = Label(top, text=f"{char} is a winner!")
    topButton = Button(top, text="Restart", command=lambda: restart(root))
    topText.grid(row=0)
    topButton.grid(row=1)


def isWinner(char):
    global root
    # horizontal
    if (((btns[1][1].cget("text") == char) and (btns[1][2].cget("text") == char) and (btns[1][3].cget("text") == char)) or
        ((btns[2][1].cget("text") == char) and (btns[2][2].cget("text") == char) and (btns[2][3].cget("text") == char)) or
        ((btns[3][1].cget("text") == char) and (btns[3][2].cget("text") == char) and (btns[3][3].cget("text") == char)) or
        # vertical
        ((btns[1][1].cget("text") == char) and (btns[2][1].cget("text") == char) and (btns[3][1].cget("text") == char)) or
        ((btns[1][2].cget("text") == char) and (btns[2][2].cget("text") == char) and (btns[3][2].cget("text") == char)) or
        ((btns[1][3].cget("text") == char) and (btns[2][3].cget("text") == char) and (btns[3][3].cget("text") == char)) or
        # diagonal
        ((btns[1][1].cget("text") == char) and (btns[2][2].cget("text") == char) and (btns[3][3].cget("text") == char)) or
            ((btns[1][3].cget("text") == char) and (btns[2][2].cget("text") == char) and (btns[3][1].cget("text") == char))):
        topMessage(char)


def main():
    global btns
    global root
    root = Tk()
    root.title("X and O of Daniar")
    root.resizable(False, False)
    btns = [None]
    for y in range(1, 4):
        row = [None]
        for x in range(1, 4):
            row.append(Button(root,
                              width=5,
                              height=3,
                              font="time 12 bold",
                              command=lambda x=x, y=y: clicked(y, x)))
            row[x].grid(row=y, column=x)
        btns.append(row)

    Button(root,
           text="Restart",
           width=5,
           command=lambda: restart(root)).grid(row=4, column=2)

    root.mainloop()


main()
  • 0
    Большое спасибо, теперь это работает! Но почему мы всегда должны использовать лямбду при вызове функции в команде?
  • 0
    Возможно, это ответит на ваш вопрос, и почему лямбда-это лучший способ реализовать эту функцию stackoverflow.com/a/47996979/8341461
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню