
作者:野客
來(lái)源:Python 技術(shù)
掃雷是一款益智類小游戲,最早于 1992 年由微軟在 Windows 上發(fā)行,游戲適合于全年齡段,規(guī)則簡(jiǎn)單,即在最短的時(shí)間內(nèi)找出所有非雷格子且在中間過(guò)程中不能踩到雷, 踩到雷則失敗,需重新開(kāi)始。
本文我們使用 Python 來(lái)實(shí)現(xiàn)掃雷游戲,主要用的 Python 庫(kù)是 pygame。
游戲組成比較簡(jiǎn)單,主要包括:小方格、計(jì)時(shí)器、地雷等。
首先,我們初始化一些常量,比如:橫豎方塊數(shù)、地雷數(shù)、鼠標(biāo)點(diǎn)擊情況等,如下所示:
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)記為問(wèn)號(hào) ask = 5 # 踩中地雷 bomb = 6 # 被雙擊的周圍 hint = 7 # 正被鼠標(biāo)左右鍵雙擊 double = 8 readied = 1, started = 2, over = 3, win = 4
接著定義一個(gè)地雷類,類中定義一些基本屬性(如:坐標(biāo)、狀態(tài)等)及 get、set 方法,代碼實(shí)現(xiàn)如下:
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')
再接著定義一個(gè) MineBlock 類,用來(lái)處理掃雷的基本邏輯,代碼實(shí)現(xiàn)如下:
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 # 如果周圍沒(méi)有雷,那么將周圍 8 個(gè)未中未點(diǎn)開(kāi)的遞歸算一遍 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
我們接下來(lái)初始化界面,首先生成由小方格組成的面板,主要代碼實(shí)現(xiàn)如下:
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)
看一下效果:
再接著添加面板的 head 部分,包括:顯示雷數(shù)、重新開(kāi)始按鈕(笑臉)、顯示耗時(shí),主要代碼實(shí)現(xiàn)如下:
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))
看一下效果:
再接著添加各種點(diǎn)擊事件,代碼實(shí)現(xiàn)如下:
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)記了所有雷,則打開(kāi)周圍一圈;如果還未標(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 = readied block = MineBlock() start_time = time.time() elapsed_time = 0 continue 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 = flag elif mine.status == flag: mine.status = ask elif mine.status == ask: mine.status = normal elif b1 and b3: if mine.status == double: block.double_mouse_button_up(x, y)
我們來(lái)看一下最終實(shí)現(xiàn)效果:
本文我們通過(guò) Python 簡(jiǎn)單的實(shí)現(xiàn)了掃雷游戲,大家有興趣的話,可以實(shí)際操作一下,看看自己能否排除全部的雷。
數(shù)據(jù)分析咨詢請(qǐng)掃描二維碼
若不方便掃碼,搜微信號(hào):CDAshujufenxi
SQL Server 中 CONVERT 函數(shù)的日期轉(zhuǎn)換:從基礎(chǔ)用法到實(shí)戰(zhàn)優(yōu)化 在 SQL Server 的數(shù)據(jù)處理中,日期格式轉(zhuǎn)換是高頻需求 —— 無(wú)論 ...
2025-09-18MySQL 大表拆分與關(guān)聯(lián)查詢效率:打破 “拆分必慢” 的認(rèn)知誤區(qū) 在 MySQL 數(shù)據(jù)庫(kù)管理中,“大表” 始終是性能優(yōu)化繞不開(kāi)的話題。 ...
2025-09-18CDA 數(shù)據(jù)分析師:表結(jié)構(gòu)數(shù)據(jù) “獲取 - 加工 - 使用” 全流程的賦能者 表結(jié)構(gòu)數(shù)據(jù)(如數(shù)據(jù)庫(kù)表、Excel 表、CSV 文件)是企業(yè)數(shù)字 ...
2025-09-18DSGE 模型中的 Et:理性預(yù)期算子的內(nèi)涵、作用與應(yīng)用解析 動(dòng)態(tài)隨機(jī)一般均衡(Dynamic Stochastic General Equilibrium, DSGE)模 ...
2025-09-17Python 提取 TIF 中地名的完整指南 一、先明確:TIF 中的地名有哪兩種存在形式? 在開(kāi)始提取前,需先判斷 TIF 文件的類型 —— ...
2025-09-17CDA 數(shù)據(jù)分析師:解鎖表結(jié)構(gòu)數(shù)據(jù)特征價(jià)值的專業(yè)核心 表結(jié)構(gòu)數(shù)據(jù)(以 “行 - 列” 規(guī)范存儲(chǔ)的結(jié)構(gòu)化數(shù)據(jù),如數(shù)據(jù)庫(kù)表、Excel 表、 ...
2025-09-17Excel 導(dǎo)入數(shù)據(jù)含缺失值?詳解 dropna 函數(shù)的功能與實(shí)戰(zhàn)應(yīng)用 在用 Python(如 pandas 庫(kù))處理 Excel 數(shù)據(jù)時(shí),“缺失值” 是高頻 ...
2025-09-16深入解析卡方檢驗(yàn)與 t 檢驗(yàn):差異、適用場(chǎng)景與實(shí)踐應(yīng)用 在數(shù)據(jù)分析與統(tǒng)計(jì)學(xué)領(lǐng)域,假設(shè)檢驗(yàn)是驗(yàn)證研究假設(shè)、判斷數(shù)據(jù)差異是否 “ ...
2025-09-16CDA 數(shù)據(jù)分析師:掌控表格結(jié)構(gòu)數(shù)據(jù)全功能周期的專業(yè)操盤手 表格結(jié)構(gòu)數(shù)據(jù)(以 “行 - 列” 存儲(chǔ)的結(jié)構(gòu)化數(shù)據(jù),如 Excel 表、數(shù)據(jù) ...
2025-09-16MySQL 執(zhí)行計(jì)劃中 rows 數(shù)量的準(zhǔn)確性解析:原理、影響因素與優(yōu)化 在 MySQL SQL 調(diào)優(yōu)中,EXPLAIN執(zhí)行計(jì)劃是核心工具,而其中的row ...
2025-09-15解析 Python 中 Response 對(duì)象的 text 與 content:區(qū)別、場(chǎng)景與實(shí)踐指南 在 Python 進(jìn)行 HTTP 網(wǎng)絡(luò)請(qǐng)求開(kāi)發(fā)時(shí)(如使用requests ...
2025-09-15CDA 數(shù)據(jù)分析師:激活表格結(jié)構(gòu)數(shù)據(jù)價(jià)值的核心操盤手 表格結(jié)構(gòu)數(shù)據(jù)(如 Excel 表格、數(shù)據(jù)庫(kù)表)是企業(yè)最基礎(chǔ)、最核心的數(shù)據(jù)形態(tài) ...
2025-09-15Python HTTP 請(qǐng)求工具對(duì)比:urllib.request 與 requests 的核心差異與選擇指南 在 Python 處理 HTTP 請(qǐng)求(如接口調(diào)用、數(shù)據(jù)爬取 ...
2025-09-12解決 pd.read_csv 讀取長(zhǎng)浮點(diǎn)數(shù)據(jù)的科學(xué)計(jì)數(shù)法問(wèn)題 為幫助 Python 數(shù)據(jù)從業(yè)者解決pd.read_csv讀取長(zhǎng)浮點(diǎn)數(shù)據(jù)時(shí)的科學(xué)計(jì)數(shù)法問(wèn)題 ...
2025-09-12CDA 數(shù)據(jù)分析師:業(yè)務(wù)數(shù)據(jù)分析步驟的落地者與價(jià)值優(yōu)化者 業(yè)務(wù)數(shù)據(jù)分析是企業(yè)解決日常運(yùn)營(yíng)問(wèn)題、提升執(zhí)行效率的核心手段,其價(jià)值 ...
2025-09-12用 SQL 驗(yàn)證業(yè)務(wù)邏輯:從規(guī)則拆解到數(shù)據(jù)把關(guān)的實(shí)戰(zhàn)指南 在業(yè)務(wù)系統(tǒng)落地過(guò)程中,“業(yè)務(wù)邏輯” 是連接 “需求設(shè)計(jì)” 與 “用戶體驗(yàn) ...
2025-09-11塔吉特百貨孕婦營(yíng)銷案例:數(shù)據(jù)驅(qū)動(dòng)下的精準(zhǔn)零售革命與啟示 在零售行業(yè) “流量紅利見(jiàn)頂” 的當(dāng)下,精準(zhǔn)營(yíng)銷成為企業(yè)突圍的核心方 ...
2025-09-11CDA 數(shù)據(jù)分析師與戰(zhàn)略 / 業(yè)務(wù)數(shù)據(jù)分析:概念辨析與協(xié)同價(jià)值 在數(shù)據(jù)驅(qū)動(dòng)決策的體系中,“戰(zhàn)略數(shù)據(jù)分析”“業(yè)務(wù)數(shù)據(jù)分析” 是企業(yè) ...
2025-09-11Excel 數(shù)據(jù)聚類分析:從操作實(shí)踐到業(yè)務(wù)價(jià)值挖掘 在數(shù)據(jù)分析場(chǎng)景中,聚類分析作為 “無(wú)監(jiān)督分組” 的核心工具,能從雜亂數(shù)據(jù)中挖 ...
2025-09-10統(tǒng)計(jì)模型的核心目的:從數(shù)據(jù)解讀到?jīng)Q策支撐的價(jià)值導(dǎo)向 統(tǒng)計(jì)模型作為數(shù)據(jù)分析的核心工具,并非簡(jiǎn)單的 “公式堆砌”,而是圍繞特定 ...
2025-09-10