python用tkinter開發(fā)的掃雷游戲
發(fā)布日期:2022-03-27 19:18 | 文章來源:腳本之家
1.實(shí)現(xiàn)效果
2.實(shí)現(xiàn)代碼
# 導(dǎo)入所需庫 from tkinter import * import random class main: # 定義一個(gè)類,繼承 tkinter 的 Button # 用來保存按鈕的狀態(tài)和在網(wǎng)格布局中的位置 class minebtn(Button): def __init__(self,master,xy,**kw): Button.__init__(self,master,**kw) self.xy = xy self._state = 0 # 狀態(tài) # 0: 未點(diǎn)開 # 1: 已點(diǎn)開 # 2: 標(biāo)記 # 3: 問號(hào) def __init__(self): # 定義規(guī)格及雷數(shù) self.width = 9 self.height = 9 self.minenum = 10 # Windows 7 默認(rèn)的三種規(guī)格和雷數(shù) # 9*9,10 # 16*16,40 # 16*32,99 self.rest = self.minenum # 剩余未標(biāo)記的雷 # 雷數(shù)的顏色 self.colorlist = ['green', # 綠色 'DodgerBlue', # 淺藍(lán)色 'DarkOrange1',# 橙色 'blue', # 藍(lán)色 '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) # 隨機(jī)抽取雷 self.mineplace = [(x%self.width,x//self.height) for x in self.mineplace] # 將雷的序號(hào)轉(zhuǎn)變?yōu)樽鴺?biāo) 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))# 左鍵單擊點(diǎn)開 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() # 點(diǎn)開 def _open(self,widget): xy = widget.xy x = xy[0] y = xy[1]# 獲取當(dāng)前按鈕的坐標(biāo) # 如果是雷則顯示全部雷的位置 if widget.xy in self.mineplace: self.showmine() return # 如果已經(jīng)點(diǎn)開了就什么也不做 if widget._state == 1: return widget.configure(relief='flat',bg='white') # 更改當(dāng)前按鈕的樣式 widget._state = 1# 按鈕狀態(tài)設(shè)為點(diǎn)開 # 獲取周圍八個(gè)雷的坐標(biāo) 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 = 0 around_ = [] for o, p in around: # 排除掉在雷區(qū)之外的雷 if 0 <= o <= self.width - 1 and 0 <= p <= self.height - 1: around_.append((o,p)) # 計(jì)算周圍的雷數(shù) if self.mines[(o,p)].xy in self.mineplace: _sum += 1 #如果周圍沒有雷則打開周圍未標(biāo)記的雷,直到有雷為止 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# 顯示雷數(shù) # 對應(yīng)數(shù)字設(shè)置對應(yīng)顏色 widget['fg'] = self.colorlist[_sum-1] # 右鍵單擊設(shè)置標(biāo)記/問號(hào) 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.另一種精致一點(diǎn)的實(shí)現(xiàn)
項(xiàng)目地址
需要導(dǎo)入額外的圖片和字體資源,在上面的項(xiàng)目地址里可以下載到
代碼
import sys import time import random import pygame from pygame.locals import * BLOCK_WIDTH = 30 BLOCK_HEIGHT = 16 # 塊大小 SIZE = 20 # 地雷數(shù) MINE_COUNT = 66 # 未點(diǎn)擊 normal = 1 # 已點(diǎn)擊 opened = 2 # 地雷 mine = 3 # 標(biāo)記為地雷 flag = 4 # 標(biāo)記為問號(hào) ask = 5 # 踩中地雷 bomb = 6 # 被雙擊的周圍 hint = 7 # 正被鼠標(biāo)左右鍵雙擊 double = 8 readied = 1, started = 2, over = 3, win = 4 class Mine: def __init__(self, x, y, value=0): self._x = x self._y = y self._value = 0 self._around_mine_count = -1 self._status = normal self.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 = 1 else: 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='四周地雷數(shù)量') 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 # 先把狀態(tài)改為 opened self._block[y][x].status = opened around = _get_around(x, y) _sum = 0 for i, j in around: if self._block[j][i].value: _sum += 1 self._block[y][x].around_mine_count = _sum # 如果周圍沒有雷,那么將周圍 8 個(gè)未中未點(diǎn)開的遞歸算一遍 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 True self._block[y][x].status = double around = _get_around(x, y) # 周圍被標(biāo)記的雷數(shù)量 sumflag = 0 for i, j in _get_around(x, y): if self._block[j][i].status == flag: sumflag += 1 # 周邊的雷已經(jīng)全部被標(biāo)記 result = True if 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 = False else: for i, j in around: if self._block[j][i].status == normal: self._block[j][i].status = hint return result def double_mouse_button_up(self, x, y): self._block[y][x].status = opened for i, j in _get_around(x, y): if self._block[j][i].status == hint: self._block[j][i].status = normal # 返回 (x, y) 周圍的點(diǎn)坐標(biāo) 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) * SIZE def 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) # 加載資源圖片,因?yàn)橘Y源文件大小不一,所以做了統(tǒng)一的縮放處理 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 # 開始時(shí)間 start_time = None # 耗時(shí) 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.pos x = mouse_x // SIZE y = mouse_y // SIZE - 2 b1, b2, b3 = pygame.mouse.get_pressed() if game_status == started: # 鼠標(biāo)左右鍵同時(shí)按下,如果已經(jīng)標(biāo)記了所有雷,則打開周圍一圈;如果還未標(biāo)記完所有雷,則有一個(gè)周圍一圈被同時(shí)按下的效果 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 = 0continue if game_status == readied: game_status = started start_time = time.time() elapsed_time = 0 if game_status == started: mine = block.getmine(x, y) # 按鼠標(biāo)左鍵 if b1 and not b3:if mine.status == normal: if not block.open_mine(x, y): game_status = over # 按鼠標(biāo)右鍵 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 = 0 opened_count = 0 for 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 += 1 elif 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 += 1 elif 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 = win if 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開發(fā)的掃雷游戲的詳細(xì)內(nèi)容,更多關(guān)于python 掃雷游戲的資料請關(guān)注本站其它相關(guān)文章!
版權(quán)聲明:本站文章來源標(biāo)注為YINGSOO的內(nèi)容版權(quán)均為本站所有,歡迎引用、轉(zhuǎn)載,請保持原文完整并注明來源及原文鏈接。禁止復(fù)制或仿造本網(wǎng)站,禁止在非www.sddonglingsh.com所屬的服務(wù)器上建立鏡像,否則將依法追究法律責(zé)任。本站部分內(nèi)容來源于網(wǎng)友推薦、互聯(lián)網(wǎng)收集整理而來,僅供學(xué)習(xí)參考,不代表本站立場,如有內(nèi)容涉嫌侵權(quán),請聯(lián)系alex-e#qq.com處理。
相關(guān)文章