# -*- coding: utf-8 -*- # @Time : 2020/12/18 12:57 # @Author : Zhenghui Lyu # @File : Main.py # @Software: PyCharm from tkinter import * from tkinter.messagebox import * import random import os import sys def new(): """重新开始游戏""" global m m.grid_remove() global model model = Model(10, 10) m = Mines(model, root) class Model: """Model类用于存储所有方块所在的(r,c)信息,有雷为1,无为0,还可检查周围雷的情况""" def __init__(self, row, col): self.width = col # 列 self.height = row # 行 self.items = [[0 for c in range(col)] for r in range(row)] def setItemValue(self, r, c, value): """设置某个位置的值为value""" self.items[r][c] = value # model.setItemValue(r, rancol, 1) def checkValue(self, r, c, value): """检查某个位置的值是否为value""" if self.items[r][c] == value: return True else: return False def countValue(self, r, c, value): """统计位置(r,c)周围8个位置,值为value的个数""" count = 0 if r - 1 >= 0 and c - 1 >= 0: if self.items[r - 1][c - 1] == 1: count += 1 if r - 1 >= 0 and c >= 0: if self.items[r - 1][c] == 1: count += 1 if r - 1 >= 0 and c + 1 <= self.width - 1: if self.items[r - 1][c + 1] == 1: count += 1 if c - 1 >= 0: if self.items[r][c - 1] == 1: count += 1 if c + 1 < self.width - 1: if self.items[r][c + 1] == 1: count += 1 if r + 1 <= self.height - 1 and c - 1 >= 0: if self.items[r + 1][c - 1] == 1: count += 1 if r + 1 <= self.height - 1: if self.items[r + 1][c] == 1: count += 1 if r + 1 <= self.height - 1 and c + 1 <= self.width - 1: if self.items[r + 1][c + 1] == 1: count += 1 return count class Mines(Frame): def __init__(self, m, master=None): Frame.__init__(self, master) self.model = m self.initmine() self.grid() self.createWidget() def createWidget(self): self.rowconfigure(self.model.height * 2, weight=1) self.columnconfigure(self.model.width * 2, weight=1) self.buttongroups = [[Button(self, height=1, width=2) for j in range(self.model.width)] for j in range(self.model.height)] for r in range(self.model.width): for c in range(self.model.height): self.buttongroups[r][c].grid(row=r, column=c, sticky=(W, E, N, S)) self.buttongroups[r][c].bind('<Button-1>', self.clickevent) self.buttongroups[r][c].bind('<Button-3>', self.Rightclickevent) self.buttongroups[r][c]['padx'] = r self.buttongroups[r][c]['pady'] = c def clickevent(self, event): r = int(str(event.widget['padx'])) c = int(str(event.widget['pady'])) if model.checkValue(r, c, 1): self.showall() else: self.recureshow(r, c) if (self.Victory()): showinfo(title='提示', message='你赢了') def Rightclickevent(self, event): r = int(str(event.widget['padx'])) c = int(str(event.widget['pady'])) if self.buttongroups[r][c]['text'] == 'X': self.buttongroups[r][c]['image'] = askImage else: self.buttongroups[r][c]['image'] = flagImage self.buttongroups[r][c]['text'] = 'X' if self.Victory(): showinfo(title='提示', message='你赢了') def Victory(self): for r in range(model.height): for c in range(model.width): if self.buttongroups[r][c]['state'] == NORMAL and self.buttongroups[r][c]['text'] != 'X': return False if model.checkValue(r, c, 0) and self.buttongroups[r][c]['text'] == 'X': return False return True def showall(self): for r in range(model.height): for c in range(model.width): self.showone(r, c) def showone(self, r, c): if model.checkValue(r, c, 0): self.buttongroups[r][c]['text'] = model.countValue(r, c, 1) else: self.buttongroups[r][c]['text'] = 'Q' self.buttongroups[r][c]['image'] = mineImage def recureshow(self, r, c): if 0 <= r <= self.model.height - 1 and 0 <= c <= self.model.width - 1: if model.checkValue(r, c, 0) and self.buttongroups[r][c]['state'] == NORMAL and model.countValue(r, c, 1) == 0: self.buttongroups[r][c]['state'] = DISABLED self.buttongroups[r][c]['bd'] = 4 self.buttongroups[r][c]['disabledforeground'] = 'red' self.buttongroups[r][c]['text'] = '0' self.recureshow(r - 1, c - 1) self.recureshow(r - 1, c) self.recureshow(r - 1, c + 1) self.recureshow(r, c - 1) self.recureshow(r, c + 1) self.recureshow(r + 1, c - 1) self.recureshow(r + 1, c) self.recureshow(r + 1, c + 1) elif model.countValue(r, c, 1) != 0: self.buttongroups[r][c]['text'] = model.countValue(r, c, 1) self.buttongroups[r][c]['state'] = DISABLED self.buttongroups[r][c]['bd'] = 4 self.buttongroups[r][c]['disabledforeground'] = 'red' else: pass def initmine(self): """埋雷,每行埋(1,height/width)个随机数量雷""" n = random.randint(1, model.height / model.width) for r in range(model.height): for i in range(n): rancol = random.randint(0, model.width - 1) model.setItemValue(r, rancol, 1) def printf(self): print('地图') for r in range(model.height): for c in range(model.width): print(model.items[r][c], end='') print('') if __name__ == '__main__': model = Model(10, 10) root = Tk() mineImage = PhotoImage(file='mine.gif') flagImage = PhotoImage(file='flag.gif') askImage = PhotoImage(file='ask.gif') menu = Menu(root) root.config(menu=menu) filemenu = Menu(menu) menu.add_cascade(label='File', menu=filemenu) filemenu.add_command(label='New', command=new) filemenu.add_separator() filemenu.add_command(label='Exit', command=root.quit) m = Mines(model, root) m.printf() root.mainloop()
扫雷游戏逻辑:
如果点击的是空白块,即周围没有地雷的块即空白块,此块编号为0,直接打开
如果点击的是周围有雷的块,则打开块并计算周围雷的数量并显示数字
如果点击的是地雷,则游戏失败
在方块上右击,显示旗帜,再次右击去掉旗帜
使用二维列表buttongroups表示若干方块按钮
二维列表items存储行列的地雷信息
用state表示方块是否被翻开
用text属性表示是否插上旗帜
浙公网安备 33010602011771号