Today I made Mine Sweeper
from tkinter import Button, Label
import random
import settings
import ctypes
import sys
class Cell:
all = []
cell_count = settings.CELL_COUNT
cell_count_label_object = None
def __init__(self,x, y, is_mine=False):
self.is_mine = is_mine
self.is_opened = False
self.is_mine_candidate = False
self.cell_btn_object = None
self.x = x
self.y = y
Cell.all.append(self)
def create_btn_object(self, location):
btn = Button(
location,
width=12,
height=4,
)
btn.bind('<Button-1>', self.left_click_actions )
btn.bind('<Button-3>', self.right_click_actions )
self.cell_btn_object = btn
@staticmethod
def create_cell_count_label(location):
lbl = Label(
location,
bg='black',
fg='white',
text=f"Cells Left:{Cell.cell_count}",
font=("", 30)
)
Cell.cell_count_label_object = lbl
def left_click_actions(self, event):
if self.is_mine:
self.show_mine()
else:
if self.surrounded_cells_mines_length == 0:
for cell_obj in self.surrounded_cells:
cell_obj.show_cell()
self.show_cell()
if Cell.cell_count == settings.MINES_COUNT:
ctypes.windll.user32.MessageBoxW(0, 'Congratulations! You won the game!', 'Game Over', 0)
self.cell_btn_object.unbind('<Button-1>')
self.cell_btn_object.unbind('<Button-3>')
def get_cell_by_axis(self, x,y):
for cell in Cell.all:
if cell.x == x and cell.y == y:
return cell
@property
def surrounded_cells(self):
cells = [
self.get_cell_by_axis(self.x - 1, self.y -1),
self.get_cell_by_axis(self.x - 1, self.y),
self.get_cell_by_axis(self.x - 1, self.y + 1),
self.get_cell_by_axis(self.x, self.y - 1),
self.get_cell_by_axis(self.x + 1, self.y - 1),
self.get_cell_by_axis(self.x + 1, self.y),
self.get_cell_by_axis(self.x + 1, self.y + 1),
self.get_cell_by_axis(self.x, self.y + 1)
]
cells = [cell for cell in cells if cell is not None]
return cells
@property
def surrounded_cells_mines_length(self):
counter = 0
for cell in self.surrounded_cells:
if cell.is_mine:
counter += 1
return counter
def show_cell(self):
if not self.is_opened:
Cell.cell_count -= 1
self.cell_btn_object.configure(text=self.surrounded_cells_mines_length)
if Cell.cell_count_label_object:
Cell.cell_count_label_object.configure(
text=f"Cells Left:{Cell.cell_count}"
)
self.cell_btn_object.configure(
bg='SystemButtonFace'
)
self.is_opened = True
def show_mine(self):
self.cell_btn_object.configure(bg='red')
ctypes.windll.user32.MessageBoxW(0, 'You clicked on a mine', 'Game Over', 0)
sys.exit()
def right_click_actions(self, event):
if not self.is_mine_candidate:
self.cell_btn_object.configure(
bg='orange'
)
self.is_mine_candidate = True
else:
self.cell_btn_object.configure(
bg='SystemButtonFace'
)
self.is_mine_candidate = False
@staticmethod
def randomize_mines():
picked_cells = random.sample(
Cell.all, settings.MINES_COUNT
)
for picked_cell in picked_cells:
picked_cell.is_mine = True
def __repr__(self):
return f"Cell({self.x}, {self.y})"
This is the code for the Cells and how they interact with the mouse actions.
from tkinter import *
from cell import Cell
import settings
import utils
root = Tk()
root.configure(bg="black")
root.geometry(f'{settings.WIDTH}x{settings.HEIGHT}')
root.title("Minesweeper Game")
root.resizable(False, False)
top_frame = Frame(
root,
bg='black',
width=settings.WIDTH,
height=utils.height_prct(25)
)
top_frame.place(x=0, y=0)
game_title = Label(
top_frame,
bg='black',
fg='white',
text='Minesweeper Game',
font=('', 48)
)
game_title.place(
x=utils.width_prct(25), y=0
)
left_frame = Frame(
root,
bg='black',
width=utils.width_prct(25),
height=utils.height_prct(75)
)
left_frame.place(x=0, y=utils.height_prct(25))
center_frame = Frame(
root,
bg='black',
width=utils.width_prct(75),
height=utils.height_prct(75)
)
center_frame.place(
x=utils.width_prct(25),
y=utils.height_prct(25),
)
for x in range(settings.GRID_SIZE):
for y in range(settings.GRID_SIZE):
c = Cell(x, y)
c.create_btn_object(center_frame)
c.cell_btn_object.grid(
column=x, row=y
)
Cell.create_cell_count_label(left_frame)
Cell.cell_count_label_object.place(
x=0, y=0
)
Cell.randomize_mines()
root.mainloop()
this is the code that controls the look of the game along with randomizing the bombs.
WIDTH=1440
HEIGHT=720
GRID_SIZE=6
CELL_COUNT=GRID_SIZE ** 2
MINES_COUNT=(CELL_COUNT) // 4
these are the settings.
import settings
def height_prct(percentage):
return (settings.HEIGHT / 100) * percentage
def width_prct(percentage):
return (settings.WIDTH / 100) * percentage
theses let you change the settings.
