您的位置:首页技术文章
文章详情页

python用tkinter开发的扫雷游戏

【字号: 日期:2022-06-17 18:46:01浏览:3作者:猪猪
目录2.实现代码3.另一种精致一点的实现1.实现效果

python用tkinter开发的扫雷游戏

python用tkinter开发的扫雷游戏

2.实现代码

# 导入所需库from tkinter import *import randomclass main: # 定义一个类,继承 tkinter 的 Button # 用来保存按钮的状态和在网格布局中的位置 class minebtn(Button):def __init__(self,master,xy,**kw): Button.__init__(self,master,**kw) self.xy = xy self._state = 0 # 状态 # 0: 未点开 # 1: 已点开 # 2: 标记 # 3: 问号def __init__(self):# 定义规格及雷数self.width = 9self.height = 9self.minenum = 10# Windows 7 默认的三种规格和雷数# 9*9,10# 16*16,40# 16*32,99self.rest = self.minenum # 剩余未标记的雷# 雷数的颜色self.colorlist = [’green’,# 绿色 ’DodgerBlue’,# 浅蓝色 ’DarkOrange1’,# 橙色 ’blue’,# 蓝色 ’red’,# 红色 ’Chocolate4’,# 棕色 ’grey’,# 灰色 ’black’]# 黑色self.setgui() def setgui(self):# GUI界面self.root = Tk()self.root.title(’扫雷’)self.restlabel = Label(self.root,text=f’剩余:{self.minenum}’)self.restlabel.grid(row=0,column=0,columnspan=3)self.mineplace = random.sample(range(self.width*self.height),self.minenum) # 随机抽取雷self.mineplace = [(x%self.width,x//self.height) for x in self.mineplace] # 将雷的序号转变为坐标self.mines = {}for y in range(self.height): for x in range(self.width):self.mines[(x,y)] = self.minebtn(self.root,xy=(x,y),font=(’黑体’,8,’bold’),width=2,bd=1,relief=’ridge’)self.mines[(x,y)].bind(’<ButtonRelease-1>’,lambda event:self._open(event.widget)) # 左键单击点开self.mines[(x,y)].bind(’<ButtonRelease-3>’,lambda event:self.make(event.widget)) # 右键单击事件self.mines[(x,y)].grid(row=y+1,column=x,sticky=’nswe’)self.root.mainloop() # 点开 def _open(self,widget):xy = widget.xyx = xy[0]y = xy[1] # 获取当前按钮的坐标# 如果是雷则显示全部雷的位置if widget.xy in self.mineplace: self.showmine() return# 如果已经点开了就什么也不做if widget._state == 1: returnwidget.configure(relief=’flat’,bg=’white’) # 更改当前按钮的样式widget._state = 1 # 按钮状态设为点开# 获取周围八个雷的坐标around = [(x-1,y-1),(x,y-1),(x+1,y-1),(x-1,y),(x+1,y),(x-1,y+1),(x,y+1),(x+1,y+1)]_sum = 0around_ = []for o, p in around: # 排除掉在雷区之外的雷 if 0 <= o <= self.width - 1 and 0 <= p <= self.height - 1:around_.append((o,p))# 计算周围的雷数if self.mines[(o,p)].xy in self.mineplace: _sum += 1#如果周围没有雷则打开周围未标记的雷,直到有雷为止if _sum == 0: widget[’text’] = ’’ for i, j in around:if self.mines[(i,j)]._state == 0: self._open(self.mines[(i,j)])else: widget[’text’] = _sum # 显示雷数 # 对应数字设置对应颜色 widget[’fg’] = self.colorlist[_sum-1] # 右键单击设置标记/问号 def make(self,widget):string = {0:’’,2:’♀’,3:’?’}if widget._state == 0: widget._state = 2 widget[’text’] = string[2] self.rest -= 1 self.restlabel[’text’] = f’剩余:{self.rest}’ elif widget._state == 2: widget._state = 3 widget[’text’] = string[3] self.rest += 1 self.restlabel[’text’] = f’剩余:{self.rest}’ elif widget._state == 3: widget._state = 0 widget[’text’] = string[0] # 如果踩到雷,显示所有的雷 def showmine(self):for i, j in self.mineplace: self.mines[(i,j)].configure(text=’ி’,fg=’red’)main()3.另一种精致一点的实现

项目地址

需要导入额外的图片和字体资源,在上面的项目地址里可以下载到

代码

import sysimport timeimport randomimport pygamefrom pygame.locals import *BLOCK_WIDTH = 30BLOCK_HEIGHT = 16# 块大小SIZE = 20# 地雷数MINE_COUNT = 66# 未点击normal = 1# 已点击opened = 2# 地雷mine = 3# 标记为地雷flag = 4# 标记为问号ask = 5# 踩中地雷bomb = 6# 被双击的周围hint = 7# 正被鼠标左右键双击double = 8readied = 1,started = 2,over = 3,win = 4class Mine: def __init__(self, x, y, value=0):self._x = xself._y = yself._value = 0self._around_mine_count = -1self._status = normalself.set_value(value) def __repr__(self):return str(self._value) def get_x(self):return self._x def set_x(self, x):self._x = x x = property(fget=get_x, fset=set_x) def get_y(self):return self._y def set_y(self, y):self._y = y y = property(fget=get_y, fset=set_y) def get_value(self):return self._value def set_value(self, value):if value: self._value = 1else: self._value = 0 value = property(fget=get_value, fset=set_value, doc=’0:非地雷 1:雷’) def get_around_mine_count(self):return self._around_mine_count def set_around_mine_count(self, around_mine_count):self._around_mine_count = around_mine_count around_mine_count = property(fget=get_around_mine_count, fset=set_around_mine_count, doc=’四周地雷数量’) def get_status(self):return self._status def set_status(self, value):self._status = value status = property(fget=get_status, fset=set_status, doc=’BlockStatus’)class MineBlock: def __init__(self):self._block = [[Mine(i, j) for i in range(BLOCK_WIDTH)] for j in range(BLOCK_HEIGHT)]# 埋雷for i in random.sample(range(BLOCK_WIDTH * BLOCK_HEIGHT), MINE_COUNT): self._block[i // BLOCK_WIDTH][i % BLOCK_WIDTH].value = 1 def get_block(self):return self._block block = property(fget=get_block) def getmine(self, x, y):return self._block[y][x] def open_mine(self, x, y):# 踩到雷了if self._block[y][x].value: self._block[y][x].status = bomb return False# 先把状态改为 openedself._block[y][x].status = openedaround = _get_around(x, y)_sum = 0for i, j in around: if self._block[j][i].value:_sum += 1self._block[y][x].around_mine_count = _sum# 如果周围没有雷,那么将周围 8 个未中未点开的递归算一遍if _sum == 0: for i, j in around:if self._block[j][i].around_mine_count == -1: self.open_mine(i, j)return True def double_mouse_button_down(self, x, y):if self._block[y][x].around_mine_count == 0: return Trueself._block[y][x].status = doublearound = _get_around(x, y)# 周围被标记的雷数量sumflag = 0for i, j in _get_around(x, y): if self._block[j][i].status == flag:sumflag += 1# 周边的雷已经全部被标记result = Trueif sumflag == self._block[y][x].around_mine_count: for i, j in around:if self._block[j][i].status == normal: if not self.open_mine(i, j):result = Falseelse: for i, j in around:if self._block[j][i].status == normal: self._block[j][i].status = hintreturn result def double_mouse_button_up(self, x, y):self._block[y][x].status = openedfor i, j in _get_around(x, y): if self._block[j][i].status == hint:self._block[j][i].status = normal# 返回 (x, y) 周围的点坐标def _get_around(x, y): return [(i, j) for i in range(max(0, x - 1), min(BLOCK_WIDTH - 1, x + 1) + 1) for j in range(max(0, y - 1), min(BLOCK_HEIGHT - 1, y + 1) + 1) if i != x or j != y]# 游戏屏幕的宽SCREEN_WIDTH = BLOCK_WIDTH * SIZE# 游戏屏幕的高SCREEN_HEIGHT = (BLOCK_HEIGHT + 2) * SIZEdef print_text(screen, font, x, y, text, fcolor=(255, 255, 255)): imgText = font.render(text, True, fcolor) screen.blit(imgText, (x, y))def main(): pygame.init() screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) pygame.display.set_caption(’扫雷’) # 得分的字体 font1 = pygame.font.Font(’resources/a.TTF’, SIZE * 2) fwidth, fheight = font1.size(’999’) red = (200, 40, 40) # 加载资源图片,因为资源文件大小不一,所以做了统一的缩放处理 img0 = pygame.image.load(’resources/0.bmp’).convert() img0 = pygame.transform.smoothscale(img0, (SIZE, SIZE)) img1 = pygame.image.load(’resources/1.bmp’).convert() img1 = pygame.transform.smoothscale(img1, (SIZE, SIZE)) img2 = pygame.image.load(’resources/2.bmp’).convert() img2 = pygame.transform.smoothscale(img2, (SIZE, SIZE)) img3 = pygame.image.load(’resources/3.bmp’).convert() img3 = pygame.transform.smoothscale(img3, (SIZE, SIZE)) img4 = pygame.image.load(’resources/4.bmp’).convert() img4 = pygame.transform.smoothscale(img4, (SIZE, SIZE)) img5 = pygame.image.load(’resources/5.bmp’).convert() img5 = pygame.transform.smoothscale(img5, (SIZE, SIZE)) img6 = pygame.image.load(’resources/6.bmp’).convert() img6 = pygame.transform.smoothscale(img6, (SIZE, SIZE)) img7 = pygame.image.load(’resources/7.bmp’).convert() img7 = pygame.transform.smoothscale(img7, (SIZE, SIZE)) img8 = pygame.image.load(’resources/8.bmp’).convert() img8 = pygame.transform.smoothscale(img8, (SIZE, SIZE)) img_blank = pygame.image.load(’resources/blank.bmp’).convert() img_blank = pygame.transform.smoothscale(img_blank, (SIZE, SIZE)) img_flag = pygame.image.load(’resources/flag.bmp’).convert() img_flag = pygame.transform.smoothscale(img_flag, (SIZE, SIZE)) img_ask = pygame.image.load(’resources/ask.bmp’).convert() img_ask = pygame.transform.smoothscale(img_ask, (SIZE, SIZE)) img_mine = pygame.image.load(’resources/mine.bmp’).convert() img_mine = pygame.transform.smoothscale(img_mine, (SIZE, SIZE)) img_blood = pygame.image.load(’resources/blood.bmp’).convert() img_blood = pygame.transform.smoothscale(img_blood, (SIZE, SIZE)) img_error = pygame.image.load(’resources/error.bmp’).convert() img_error = pygame.transform.smoothscale(img_error, (SIZE, SIZE)) face_size = int(SIZE * 1.25) img_face_fail = pygame.image.load(’resources/face_fail.bmp’).convert() img_face_fail = pygame.transform.smoothscale(img_face_fail, (face_size, face_size)) img_face_normal = pygame.image.load(’resources/face_normal.bmp’).convert() img_face_normal = pygame.transform.smoothscale(img_face_normal, (face_size, face_size)) img_face_success = pygame.image.load(’resources/face_success.bmp’).convert() img_face_success = pygame.transform.smoothscale(img_face_success, (face_size, face_size)) face_pos_x = (SCREEN_WIDTH - face_size) // 2 face_pos_y = (SIZE * 2 - face_size) // 2 img_dict = {0: img0, 1: img1, 2: img2, 3: img3, 4: img4, 5: img5, 6: img6, 7: img7, 8: img8} bgcolor = (225, 225, 225) block = MineBlock() game_status = readied # 开始时间 start_time = None # 耗时 elapsed_time = 0 while True:screen.fill(bgcolor)for event in pygame.event.get(): if event.type == QUIT:sys.exit() elif event.type == MOUSEBUTTONDOWN:mouse_x, mouse_y = event.posx = mouse_x // SIZEy = mouse_y // SIZE - 2b1, b2, b3 = pygame.mouse.get_pressed()if game_status == started: # 鼠标左右键同时按下,如果已经标记了所有雷,则打开周围一圈;如果还未标记完所有雷,则有一个周围一圈被同时按下的效果 if b1 and b3:mine = block.getmine(x, y)if mine.status == opened: if not block.double_mouse_button_down(x, y):game_status = over elif event.type == MOUSEBUTTONUP:if y < 0: if face_pos_x <= mouse_x <= face_pos_x + face_size and face_pos_y <= mouse_y <= face_pos_y + face_size:game_status = readiedblock = MineBlock()start_time = time.time()elapsed_time = 0continueif game_status == readied: game_status = started start_time = time.time() elapsed_time = 0if game_status == started: mine = block.getmine(x, y) # 按鼠标左键 if b1 and not b3:if mine.status == normal: if not block.open_mine(x, y):game_status = over # 按鼠标右键 elif not b1 and b3:if mine.status == normal: mine.status = flagelif mine.status == flag: mine.status = askelif mine.status == ask: mine.status = normal elif b1 and b3:if mine.status == double: block.double_mouse_button_up(x, y)flag_count = 0opened_count = 0for row in block.block: for mine in row:pos = (mine.x * SIZE, (mine.y + 2) * SIZE)if mine.status == opened: screen.blit(img_dict[mine.around_mine_count], pos) opened_count += 1elif mine.status == double: screen.blit(img_dict[mine.around_mine_count], pos)elif mine.status == bomb: screen.blit(img_blood, pos)elif mine.status == flag: screen.blit(img_flag, pos) flag_count += 1elif mine.status == ask: screen.blit(img_ask, pos)elif mine.status == hint: screen.blit(img0, pos)elif game_status == over and mine.value: screen.blit(img_mine, pos)elif mine.value == 0 and mine.status == flag: screen.blit(img_error, pos)elif mine.status == normal: screen.blit(img_blank, pos)print_text(screen, font1, 30, (SIZE * 2 - fheight) // 2 - 2, ’%02d’ % (MINE_COUNT - flag_count), red)if game_status == started: elapsed_time = int(time.time() - start_time)print_text(screen, font1, SCREEN_WIDTH - fwidth - 30, (SIZE * 2 - fheight) // 2 - 2, ’%03d’ % elapsed_time, red)if flag_count + opened_count == BLOCK_WIDTH * BLOCK_HEIGHT: game_status = winif game_status == over: screen.blit(img_face_fail, (face_pos_x, face_pos_y))elif game_status == win: screen.blit(img_face_success, (face_pos_x, face_pos_y))else: screen.blit(img_face_normal, (face_pos_x, face_pos_y))pygame.display.update()if __name__ == ’__main__’: main()

以上就是python用tkinter开发的扫雷游戏的详细内容,更多关于python 扫雷游戏的资料请关注好吧啦网其它相关文章!

标签: Python 编程
相关文章: