I designed a game of Minesweeper where the board was displayed using text, and it worked fine. Using the same pseudocode, I tried to write the game with a GUI using Tkinter, and made a few modifications to account for having a GUI. Here is my code:
import random
import tkinter as tk
from tkinter import messagebox
def create_game_gui():
for widget in root.slaves():
widget.destroy()
for row in range(board_width):
for column in range(board_height):
if display_array[row][column]:
tile_button = tk.Button(root, text=str(data_array[row][column]), height=tile_size, width=tile_size)
tile_button["state"] = tk.DISABLED
tile_button.grid(row=row, column=column)
tile_button.bind("<Button-2>", lambda event, row=row, column=column: quick_uncover(event, row, column))
tile_button.bind("<Button-3>", lambda event, row=row, column=column: quick_uncover(event, row, column))
else:
if flag_array[row][column]:
text = "F"
else:
text = " "
if data_array[row][column] == -1:
tile_button = tk.Button(root, text=text, height=tile_size, width=tile_size, command=game_over)
elif data_array[row][column] == 0:
tile_button = tk.Button(root, text=text, height=tile_size, width=tile_size, command=lambda row=row, column=column: flip_zero(row, column))
else:
tile_button = tk.Button(root, text=text, height=tile_size, width=tile_size, command=lambda row=row, column=column: flip_number(row, column))
tile_button.bind("<Button-2>", lambda event, row=row, column=column: flag(event, row, column))
tile_button.bind("<Button-3>", lambda event, row=row, column=column: flag(event, row, column))
tile_button.grid(row=row, column=column)
def game_over():
messagebox.showerror("Game Over", "You lost!")
exit()
def flip_adjacent_zeros(start_row, start_column):
display_array[start_row][start_column] = True
for row in range(max(0, start_row - 1), min(board_height - 1, start_row + 1) + 1):
for column in range(max(0, start_column - 1), min(board_width - 1, start_column + 1) + 1):
if data_array[row][column] == 0 and not display_array[row][column]:
flip_adjacent_zeros(row, column)
display_array[row][column] = True
def flip_zero(start_row, start_column):
flip_adjacent_zeros(start_row, start_column)
create_game_gui()
def flip_number(row, column):
display_array[row][column] = True
if data_array[row][column] == -1:
game_over()
create_game_gui()
def quick_uncover(event, start_row, start_column):
for row in range(max(0, start_row - 1), min(board_height - 1, start_row + 1) + 1):
for column in range(max(0, start_column - 1), min(board_width - 1, start_column + 1) + 1):
if not flag_array[row][column]:
if data_array[row][column] == -1:
game_over()
elif data_array[row][column] == 0:
flip_adjacent_zeros(row, column)
else:
display_array[row][column] = True
create_game_gui()
def flag(event, row, column):
if flag_array[row][column]:
flag_array[row][column] = False
else:
flag_array[row][column] = True
create_game_gui()
def generate_board():
board = [[0 for x in range(board_width)] for y in range(board_height)]
generated_mines = 0
while generated_mines < mines:
random_row = random.randint(0, board_height - 1)
random_column = random.randint(0, board_height - 1)
if board[random_row][random_column] != -1:
generated_mines += 1
board[random_row][random_column] = -1
for row in range(max(0, random_row - 1), min(board_height - 1, random_row + 1) + 1):
for column in range(max(0, random_column - 1), min(board_width - 1, random_column + 1) + 1):
if board[row][column] != -1:
board[row][column] += 1
return board
if __name__ == "__main__":
root = tk.Tk()
root.title("Minesweeper")
board_width = 10
board_height = 10
mines = 10
tile_size = 3
unopened_safe_tiles = board_width * board_height - mines
data_array = generate_board()
display_array = [[False for x in range(board_width)] for y in range(board_height)]
flag_array = [[False for x in range(board_width)] for y in range(board_height)]
create_game_gui()
tk.mainloop()
Right now, the code that draws the game state onto the screen is incredibly slow. I can see each individual Button being deleted and placed again. If I change the board size to anything bigger, the game gets very laggy as the game goes on. How can I optimize my program?