Adding the timer, smiley face, and flags in Minesweeper. - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: GUI (https://python-forum.io/forum-10.html) +--- Thread: Adding the timer, smiley face, and flags in Minesweeper. (/thread-33540.html) |
Adding the timer, smiley face, and flags in Minesweeper. - javesike1262 - May-03-2021 Hi everyone, A friend of mine and I have been working on a Minesweeper game created in Python in Tkinter. We have almost completed programming the game and all we just need is to create the timer, smiley face and the flags and this is where we have been stuck on. import random import tkinter from tkinter import * from tkinter import ttk from tkinter import messagebox root = Tk() root.title("Minesweeper") root.columnconfigure(0, weight=1) root.rowconfigure(0, weight=1) mainframe = ttk.Frame(root, padding="12 12 12 12") mainframe.grid(column=0, row=0, sticky=(N, W, E, S)) def right_click(): print("D") def label_in(label): global label_list global keep_going row = label.widget.grid_info()["row"] column = label.widget.grid_info()["column"] number = row * columns + column counter = 0 if str(num_array[number]) == "X" and keep_going: for i in range(len(label_list)): if num_array[i] == "X": label_list[i].configure(text = " X", relief = "sunken") ttk.Label(mainframe, text= "You lost! Try again").grid(column= 0, row=21, columnspan=20) keep_going = False elif str(num_array[number]) != "X" and keep_going: label.widget.configure(text = " " + str(num_array[number]), relief = "sunken") label_list[number] = "FIN" for i in range(len(label_list)): if label_list[i] != "FIN": counter +=1 if counter == bomb_amount: for i in range(len(label_list)): if num_array[i] == "X": label_list[i].configure(text = " X", relief = "sunken") ttk.Label(mainframe, text= "You Won! Play again").grid(column= 0, row=5, columnspan= 20) keep_going = False def board_create(num_array): global label_list label_list = [] count = 0 column = 0 row = 0 for i in range(len(num_array)): if column == (columns): column = 0 row += 1 # label_creation = ttk.Label(mainframe, text = " ", relief = "raised", width= 3) label_list.append(ttk.Label(mainframe, text = " ", relief = "raised", width= 3)) label_list[i].grid(column = column, row = row) column += 1 count+=1 label_list[i].bind("<Button-1>", label_in) label_list[i].bind("<Button-2>", right_click) def get_array(): rowxcolumn = rows * columns number_array = [0]*rowxcolumn for i in range(bomb_amount): bomb = random.randint(1,len(number_array) -1) if number_array[bomb] != "X": number_array[bomb] = "X" double_check = 1 count = 0 [print(number_array[rowxcolumn-columns-1])] print(len(number_array)) for i in range(len(number_array)): if count == 0 and number_array[count] != "X" and number_array[count] < double_check: if number_array[count+1] == "X": number_array[count] += 1 if number_array[count+columns] == "X": number_array[count] += 1 if number_array[count+columns+1] == "X": number_array[count] += 1 if count == (columns) and number_array[count] != "X" and number_array[count] < double_check : if number_array[count-1] == "X": number_array[count] += 1 if number_array[count+columns] == "X": number_array[count] += 1 if number_array[count+columns-1] == "X": number_array[count] += 1 if count == (rowxcolumn-1) and number_array[count] != "X" and number_array[count] < double_check : if number_array[count-1] == "X": number_array[count] += 1 if number_array[count-columns] == "X": number_array[count] += 1 if number_array[count-columns-1] == "X": number_array[count] += 1 if count == (rowxcolumn-columns)and number_array[count] != "X" and number_array[count] < double_check: if number_array[count+1] == "X": number_array[count] += 1 if number_array[count-columns] == "X": number_array[count] += 1 if number_array[count-columns+1] == "X": number_array[count] += 1 if count < (columns) and number_array[count] != "X" and not(count == columns-1) and not(count == rowxcolumn-1) and number_array[count] < double_check and (not count == 0): if number_array[count-1] == "X": number_array[count] += 1 if number_array[count+1] == "X": number_array[count] += 1 if number_array[count+columns] == "X": number_array[count] += 1 if number_array[count+columns+1] == "X": number_array[count] += 1 if number_array[count+columns-1] == "X": number_array[count] += 1 if count > (rowxcolumn-columns-1) and number_array[count] != "X" and not(count == rowxcolumn-1) and not(count == rowxcolumn-columns) and number_array[count] < double_check : if number_array[count-1] == "X": number_array[count] += 1 if number_array[count+1] == "X": number_array[count] += 1 if number_array[count-columns] == "X": number_array[count] += 1 if number_array[count-columns-1] == "X": number_array[count] += 1 if number_array[count-columns+1] == "X": number_array[count] += 1 if count % (columns) == (columns -1) and not(count == 0) and not(count == columns-1) and not(count == rowxcolumn-1) and not(count == rowxcolumn-columns) and number_array[count] != "X" and number_array[count] < double_check : if number_array[count-1] == "X": number_array[count] += 1 if number_array[count+columns] == "X": number_array[count] += 1 if number_array[count-columns] == "X": number_array[count] += 1 if number_array[count-columns-1] == "X": number_array[count] += 1 if number_array[count+columns-1] == "X": number_array[count] += 1 if count % (columns) == 0 and not(count == 0) and not(count == columns-1) and not(count == rowxcolumn-1) and not(count == rowxcolumn-columns-1) and number_array[count] != "X" and count < (rowxcolumn-columns-1) and number_array[count]< double_check: if number_array[count+1] == "X": number_array[count] += 1 if number_array[count+columns] == "X": number_array[count] += 1 if number_array[count-columns] == "X": number_array[count] += 1 if number_array[count-columns+1] == "X": number_array[count] += 1 if number_array[count+columns+1] == "X": number_array[count] += 1 if not(count % (columns) == 0) and not(count%columns == (columns-1)) and count > columns and count < (rowxcolumn-columns-1) and number_array[count] != "X" and number_array[count] < double_check: if number_array[count+1] == "X": number_array[count] += 1 if number_array[count-1] == "X": number_array[count] += 1 if number_array[count+columns] == "X": number_array[count] += 1 if number_array[count-columns] == "X": number_array[count] += 1 if number_array[count-columns+1] == "X": number_array[count] += 1 if number_array[count-columns-1] == "X": number_array[count] += 1 if number_array[count+columns+1] == "X": number_array[count] += 1 if number_array[count+columns-1] == "X": number_array[count] += 1 count += 1 double_check += 1 for i in range(len(number_array)): print(str(number_array[i]), end = " ") if i % columns == columns - 1: print("") count = 0 return number_array bomb_amount = 30 rows = 20 columns = 20 num_array = get_array() label_list = [] board_create(num_array) keep_going = True root.mainloop() RE: Adding the timer, smiley face, and flags in Minesweeper. - Axel_Erfurt - May-03-2021 Use insert python and not pastebin. RE: Adding the timer, smiley face, and flags in Minesweeper. - deanhystad - May-03-2021 You would get a lot of benefit from a couple of simple classes. This is my attempt at Minesweeper using classes to represent the map and a single cell of the map. The cell knows how to do all the cell things like placing a flag marker (I used "F" instead of an image) or exposing the bomb our bomb count info. The board class creates all the cells and could easily be enhanced to display a remaining safe cell count and win/lose messages. import random import tkinter as tk class Cell(tk.Button): """A button for the Minsweeper game. Press me to reveal a bomb or information about surrounding bombs. """ def __init__(self, parent, row, column, count): super().__init__(parent, text=' ', width=2, relief=tk.RAISED, command=self.press) self.parent = parent self.row = row self.column = column self.count = count self.pressed = False self.flagged = False self.bind("<Button-3>", self.flag) def press(self): """Button pressed. Show bomb info""" if not self.pressed: self.configure(relief=tk.SUNKEN) self.pressed = True self['text'] = 'X' if self.count < 0 else str(self.count) self.parent.clear_cell(self) def flag(self, _): """Right mouse button pressed. Toggle flag marker""" if not self.pressed: self.flagged = not self.flagged self['text'] = 'F' if self.flagged else ' ' class Board(tk.Frame): """Map for Minesweeper game. I make a grid of buttons that are pressed to reveal bombs or information about surrounding bombs. """ def __init__(self, parent, rows, columns, bomb_count): super().__init__(parent) self.safe_count = rows * columns - bomb_count # Make map of all the bombs bombs = [[0]*columns for row in range(rows)] for bomb in random.choices(range(rows*columns), k=bomb_count): bombs[bomb // columns][bomb % columns] = 1 # Make the board map self.cells = [] for row in range(rows): for column in range(columns): # Count bombs in surrounding cells. Use -1 to indicate cell has bomb if bombs[row][column]: count = -1 else: count = sum([bombs[r][c] for r in range(max(0, row-1), min(rows, row+2)) \ for c in range(max(0, column-1), min(columns, column+2))]) cell = Cell(self, row, column, count) cell.grid(row=row, column=column) self.cells.append(cell) def clear_cell(self, cell): """Cell was selected""" if cell.count < 0: print('BOOM!!!') else: self.safe_count -= 1 if self.safe_count <= 0: print('You won!!') root = tk.Tk() root.title("Minesweeper") root.columnconfigure(0, weight=1) root.rowconfigure(0, weight=1) board = Board(root, 20, 20, 30) board.grid(column=0, row=0, sticky='NEWS') root.mainloop() RE: Adding the timer, smiley face, and flags in Minesweeper. - deanhystad - May-03-2021 Images in buttons is pretty easy. Just create an image for the flag, then when you flag a cell set the text to '' and set the image. I clipped this from a tk Yahtzee game. import pathlib import tkinter as tk import random IMAGE_DIR = pathlib.Path(__file__).parent class DiceButton(tk.Button): """Roll a die""" def __init__(self, parent): # Create dice images self.images = [tk.PhotoImage(file=IMAGE_DIR/f'dice{i}.png') for i in range(7)] super().__init__(parent, image=self.images[0], command=self.roll) self.value = 0 def roll(self): self.value = random.randint(1, 6) self['image'] = self.images[self.value] ROOT = tk.Tk() for _ in range(6): DiceButton(ROOT).pack(side=tk.LEFT) ROOT.mainloop() RE: Adding the timer, smiley face, and flags in Minesweeper. - javesike1262 - May-03-2021 Thanks for the suggestions we are good at keeping the good long as we tend to learn more but I just want the right click function and the smiley face and numbers just like the real minesweeper. RE: Adding the timer, smiley face, and flags in Minesweeper. - deanhystad - May-04-2021 For a timer you'll need a periodic event. For something like this the easiest way to do something periodically is use the "after()" method. Here I added a status line to the bottom of the window which is updated every second to show elapsed time. import random import time import datetime import tkinter as tk from tkinter import messagebox class Cell(tk.Button): """A button for the Minsweeper game. Press me to reveal a bomb or information about surrounding bombs. """ def __init__(self, parent, row, column, count): super().__init__(parent, text=' ', width=2, relief=tk.RAISED, command=self.press) self.parent = parent self.row = row self.column = column self.count = count self.pressed = False self.flagged = False self.bind("<Button-3>", self.flag) def press(self): """Button pressed. Show bomb info""" if not self.pressed: self.configure(relief=tk.SUNKEN) self.pressed = False self['text'] = 'X' if self.count < 0 else str(self.count) self.parent.clear_cell(self) def flag(self, _): """Right mouse button pressed. Toggle flag marker""" if not self.pressed: self.flagged = not self.flagged self['text'] = 'F' if self.flagged else ' ' class Board(tk.Frame): """Map for Minesweeper game. I make a grid of buttons that are pressed to reveal bombs or information about surrounding bombs. """ def __init__(self, parent, rows, columns, bomb_count): super().__init__(parent) self.safe_count = rows * columns - bomb_count # Make map of all the bombs bombs = [[0]*columns for row in range(rows)] for bomb in random.choices(range(rows*columns), k=bomb_count): bombs[bomb // columns][bomb % columns] = 1 # Make the board map self.cells = [] for row in range(rows): for column in range(columns): # Count bombs in surrounding cells. Use -1 to indicate cell has bomb if bombs[row][column]: count = -1 else: count = sum([bombs[r][c] for r in range(max(0, row-1), min(rows, row+2)) \ for c in range(max(0, column-1), min(columns, column+2))]) cell = Cell(self, row, column, count) cell.grid(row=row, column=column) self.cells.append(cell) # Add status display to bottom of window self.done = False self.status = tk.Label(parent, text='') self.status.grid(row=rows, column=0, columnspan=columns) self.start_time = time.time() self.update_status() def clear_cell(self, cell): """Cell was selected""" if cell.count < 0: self.done = True messagebox.showinfo('Game Over', 'Today marks the passing of you') else: self.safe_count -= 1 if self.safe_count <= 0: self.done = True messagebox.showinfo('Game Over', 'Winner, winner, chicken dinner!') def update_status(self): """Update status display""" delta = str(datetime.timedelta(seconds=int(time.time() - self.start_time))) self.status['text'] = f'{delta} Remaining {self.safe_count}' if not self.done: self.after(1000, self.update_status) # Run again after 1 second root = tk.Tk() root.title("Minesweeper") root.columnconfigure(0, weight=1) root.rowconfigure(0, weight=1) board = Board(root, 20, 20, 30) board.grid(column=0, row=0, sticky='NEWS') root.mainloop() |