Моя программа тральщика работает отлично, пока я не нажму на верхнюю левую плитку.

Я пытаюсь сделать тральщик в Python с помощью tkinter. Когда программа проверяет наличие бомб, она работает нормально, если только щелчок плитки не равен 0, 0 (вверху слева), и в этом случае программа всегда имеет tileNorth и tileWest True, в результате чего программа проверяет переменную, которая не существует. Это вызывает ошибку и оставляет ячейку 0, 0 пустой. Проверка работает в любой другой плитке, включая углы, только не в верхнем левом углу. Этого не должно быть.

TLDR: Моя программа тральщика работает просто отлично, но она всегда сбивается с 0, 0 и выдает ошибку. Я не понимаю, что не так ...

Ошибка:

Exception in Tkinter callback
Traceback (most recent call last):
  File "/usr/lib/python3.7/tkinter/__init__.py", line 1705, in __call__
    return self.func(*args)
  File "<string>", line 11, in <lambda>
  File "/home/pi/Documents/Python/Minesweeper/Minesweeper.py", line 133, in tileClicked
    stringVar_{x}_{y}.set(tileValue)""")
  File "<string>", line 56
    if bomb_-1_-1 == True:
              ^
SyntaxError: invalid token

В нем упоминается bomb_-1_-1, который не существует и не может существовать ... Вот почему этот оператор должен работать.

Мой код:


import random
import tkinter

# Functions

def tileClicked(x, y): # Function is ran when a tile is clicked. The tile is defined by the inputted 'x' and 'y' values.

    exec(f"""

global tileNorth, tileEast, tileSouth, tileWest

if y > 0:
    tileNorth = True

else:
    tileNorth = False

if x < game.size[0] - 1:
    tileEast = True

else:
    tileEast = False

if y < game.size[1] - 1:
    tileSouth = True

else:
    tileSouth = False

if x > 0:
    tileWest = True

else:
    tileWest = False""")

    print(f"""{tileNorth}
{tileEast}
{tileSouth}
{tileWest}
DIV""")

    exec(f"""

print("{x}, {y}")

if bomb_{x}_{y} == True:
    stringVar_{x}_{y}.set("Bomb")
    game.failed = True

if x == 0 and y == 0:
    tileValue = int(0)

    if tileNorth == True:

        if tileEast == True:

            if bomb_{x + 1}_{y - 1} == True:
                tileValue += 1

    if tileEast == True:

        if bomb_{x + 1}_{y} == True:
            tileValue += 1

    if tileSouth == True:

        if tileEast == True:

            if bomb_{x + 1}_{y + 1} == True:
                tileValue += 1

        if tileWest == True:

            if bomb_{x - 1}_{y + 1} == True:
                tileValue += 1

        if bomb_{x}_{y + 1} == True:
            tileValue += 1

    if tileWest == True:

        if bomb_{x - 1}_{y} == True:
            tileValue += 1

else:
    tileValue = int(0)

    if tileNorth == True:

        if tileEast == True:

            if bomb_{x + 1}_{y - 1} == True:
                tileValue += 1

        if tileWest == True:

            if bomb_{x - 1}_{y - 1} == True:
                tileValue += 1

        if bomb_{x}_{y - 1} == True:
            tileValue += 1

    if tileEast == True:

        if bomb_{x + 1}_{y} == True:
            tileValue += 1

    if tileSouth == True:

        if tileEast == True:

            if bomb_{x + 1}_{y + 1} == True:
                tileValue += 1

        if tileWest == True:

            if bomb_{x - 1}_{y + 1} == True:
                tileValue += 1

        if bomb_{x}_{y + 1} == True:
            tileValue += 1

    if tileWest == True:

        if bomb_{x - 1}_{y} == True:
            tileValue += 1

    if tileValue == 0:
        tileValue = "Clear"

    stringVar_{x}_{y}.set(tileValue)""")

# Classes

class game:
    title = "Minesweeper"
    bg = "white"
    fg = "black"
    size = [10, 10]
    tileWidth = 3
    tileHeight = 2
    failed = False
    bombFrequency = 4
    flagMode = False

# Execution

window = tkinter.Tk() # The window.
window.title(game.title)
window.config(bg = game.bg)

mainFrame = tkinter.Frame(window, bg = game.bg) # Main frame that everything is located in.

titleFrame = tkinter.Frame(mainFrame, bg = game.bg) # Title frame.
titleLabel = tkinter.Label(titleFrame, bg = game.bg, fg = game.fg, text = game.title, font = "none 20").grid(row = 0, column = 0)
titleFrame.grid(row = 0, column = 0)

tileFrame = tkinter.Frame(mainFrame, bg = game.bg) # Frame where tiles are located.

x = 0
y = 0

for tiles_x in range(game.size[0]): # Generates tiles.

    for tiles_y in range(game.size[1]):

        exec(f"""global tile_{x}_{y}, stringVar_{x}_{y}, bomb_{x}_{y}
bomb_{x}_{y} = random.randint(1, game.bombFrequency)

if bomb_{x}_{y} == 1:
    bomb_{x}_{y} = True

else:
    bomb_{x}_{y} = False

stringVar_{x}_{y} = tkinter.StringVar(tileFrame)
tile_{x}_{y} = tkinter.Button(tileFrame, bg = 'lightgrey', fg = 'black', width = game.tileWidth, height = game.tileHeight, textvariable = stringVar_{x}_{y}, command = lambda: tileClicked({x}, {y})).grid(row = {y}, column = {x})""")

        y += 1

    x += 1
    y = 0

tileFrame.grid(row = 1, column = 0)

mainFrame.pack() # The main frame is packed so everything is centered.

window.mainloop()

Мне все равно, если вы думаете, что динамические переменные неэффективны, это мой выбор. Я не хочу, чтобы люди комментировали мои методы выполнения задачи ... если только это не вызывает проблемы ...

Благодарность!

Всего 1 ответ


Использование динамических переменных - плохая практика, а ваш опыт - хорошая демонстрация того, почему.

Имена переменных не могут иметь знак минус. Знак минус интерпретируется как арифметический оператор. Таким образом, bomb_-1_-1 интерпретируется как bomb_ - 1_ - 1 . Часть bomb_ понимается как имя переменной, а 1 как число, но подчеркивание после этого числа вызывает синтаксическую ошибку.

Это также демонстрирует, что динамический код не так уж и хорош: синтаксические ошибки появляются только при определенных обстоятельствах (например, при выборе конкретной ячейки).

Быстрое решение проблемы - сначала проверить значения x и y :

if {x} >= 0 and {y} >= 0 and bomb_{x}_{y} == True:

Вы должны будете сделать подобные тесты для любого другого места, где вы создаете динамическую ссылку, подобную этой. Поэтому также:

if {x} >= 1 and {y} >= 1 and bomb_{x-1}_{y-1} == True:

...и т.д.

Но это действительно исправление ужасного дизайна.

Обратите внимание, что даже если только одна из переменных является отрицательной, вы оцените выражение, которое вы на самом деле не намеревались. Вы можете получить это, когда только y == -1 : bomb_5_-1 . Это не приводит к синтаксической ошибке, но оценивается как bomb_5_ минус 1 . Очевидно, что это не предусмотрено алгоритмом.

Вместо динамических переменных и анализа кода во время выполнения используйте списки. Они могут быть вложенными, чтобы иметь 2D покрытие.


Есть идеи?

10000