Python:遊戲:掃雷
這次我們基於 pygame 來做一個掃雷,上次有園友問我程式碼的 python 版本,我說明一下,我所有的程式碼都是基於 python 3.6 的。
先看截圖,仿照 XP 上的掃雷做的,感覺 XP 上的樣式比 win7 上的好看多了。
原諒我手殘,掃雷基本就沒贏過,測試的時候我是偷偷的把雷的數量從99改到50才贏了。。。
程式碼雖然不多,但加上註釋和空行也有350行,另外還有一些圖片資源,就不全帖上來了,完整的程式碼和資源我放到CSDN上了,感興趣的小夥伴可以去下載一下。下載地址
下面將一下我的實現邏輯。
首先,如何表示雷和非雷,一開始想的是,建立一個二維陣列表示整個區域,0表示非地雷,1表示地雷。後來一想不對,還有標記為地雷,標記為問號,還有表示周邊雷數的數字,好多狀態,乾脆就做個類吧
class BlockStatus(Enum): normal = 1 # 未點選 opened = 2 # 已點選 mine = 3 # 地雷 flag = 4 # 標記為地雷 ask = 5 # 標記為問號 bomb = 6 # 踩中地雷 hint = 7 # 被雙擊的周圍 double = 8 # 正被滑鼠左右鍵雙擊 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 = BlockStatus.normal self.set_value(value) def __repr__(self): return str(self._value) # return f'({self._x},{self._y})={self._value}, status={self.status}' 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='四周地雷數量') 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')
佈雷就很簡單了,隨機取99個數,從上往下順序排就是了。
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
我們點選一個格子的時候,只要根據點選的座標,找到對應的 Mine,看它的值是多少,就知道有沒有踩中雷了。
如果沒踩中雷的話,要計算周邊8個位置中有幾個雷,以便顯示對應的數字。
如果周邊有雷,那麼顯示數字,這個簡單,可是如果周邊沒有雷,那就要顯示一片區域,直到有雷出現,如下圖,我只點了當中一下,就出現了那麼大一片區域
這個計算其實也容易,只要用遞迴就可以了,如果計算出周圍的雷數為0,則遞迴計算周邊8個位置的四周雷數,直到雷數不為0。
class MineBlock:
def open_mine(self, x, y):
# 踩到雷了
if self._block[y][x].value:
self._block[y][x].status = BlockStatus.bomb
return False
# 先把狀態改為 opened
self._block[y][x].status = BlockStatus.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個未中未點開的遞迴算一遍
# 這就能實現一點出現一大片開啟的效果了
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 _get_around(x, y):
"""返回(x, y)周圍的點的座標"""
# 這裡注意,range 末尾是開區間,所以要加 1
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]
接下來還有一個麻煩的地方,我們經常滑鼠左右鍵同時按下,如果雷被全部標記,則會一下子開啟周圍所有的格子,如果其中有標記錯的,那麼不好意思,GAME OVER。
如果沒有全標記完,會有一個效果顯示周圍一圈未被開啟和標記的格子
class MineBlock:
def double_mouse_button_down(self, x, y):
if self._block[y][x].around_mine_count == 0:
return True
self._block[y][x].status = BlockStatus.double
around = _get_around(x, y)
sumflag = 0 # 周圍被標記的雷數量
for i, j in _get_around(x, y):
if self._block[j][i].status == BlockStatus.flag:
sumflag += 1
# 周邊的雷已經全部被標記
result = True
if sumflag == self._block[y][x].around_mine_count:
for i, j in around:
if self._block[j][i].status == BlockStatus.normal:
if not self.open_mine(i, j):
result = False
else:
for i, j in around:
if self._block[j][i].status == BlockStatus.normal:
self._block[j][i].status = BlockStatus.hint
return result
def double_mouse_button_up(self, x, y):
self._block[y][x].status = BlockStatus.opened
for i, j in _get_around(x, y):
if self._block[j][i].status == BlockStatus.hint:
self._block[j][i].status = BlockStatus.normal
掃雷的主要邏輯就這麼多,剩下來的就是一些雜七雜八的事件了。程式碼也帖一下吧
import sys
import time
from enum import Enum
import pygame
from pygame.locals import *
from mineblock import *
# 遊戲螢幕的寬
SCREEN_WIDTH = BLOCK_WIDTH * SIZE
# 遊戲螢幕的高
SCREEN_HEIGHT = (BLOCK_HEIGHT + 2) * SIZE
class GameStatus(Enum):
readied = 1,
started = 2,
over = 3,
win = 4
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)
# 載入資源圖片,因為資原始檔大小不一,所以做了統一的縮放處理
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 = GameStatus.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.pos
x = mouse_x // SIZE
y = mouse_y // SIZE - 2
b1, b2, b3 = pygame.mouse.get_pressed()
if game_status == GameStatus.started:
# 滑鼠左右鍵同時按下,如果已經標記了所有雷,則開啟周圍一圈
# 如果還未標記完所有雷,則有一個周圍一圈被同時按下的效果
if b1 and b3:
mine = block.getmine(x, y)
if mine.status == BlockStatus.opened:
if not block.double_mouse_button_down(x, y):
game_status = GameStatus.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 = GameStatus.readied
block = MineBlock()
start_time = time.time()
elapsed_time = 0
continue
if game_status == GameStatus.readied:
game_status = GameStatus.started
start_time = time.time()
elapsed_time = 0
if game_status == GameStatus.started:
mine = block.getmine(x, y)
if b1 and not b3: # 按滑鼠左鍵
if mine.status == BlockStatus.normal:
if not block.open_mine(x, y):
game_status = GameStatus.over
elif not b1 and b3: # 按滑鼠右鍵
if mine.status == BlockStatus.normal:
mine.status = BlockStatus.flag
elif mine.status == BlockStatus.flag:
mine.status = BlockStatus.ask
elif mine.status == BlockStatus.ask:
mine.status = BlockStatus.normal
elif b1 and b3:
if mine.status == BlockStatus.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 == BlockStatus.opened:
screen.blit(img_dict[mine.around_mine_count], pos)
opened_count += 1
elif mine.status == BlockStatus.double:
screen.blit(img_dict[mine.around_mine_count], pos)
elif mine.status == BlockStatus.bomb:
screen.blit(img_blood, pos)
elif mine.status == BlockStatus.flag:
screen.blit(img_flag, pos)
flag_count += 1
elif mine.status == BlockStatus.ask:
screen.blit(img_ask, pos)
elif mine.status == BlockStatus.hint:
screen.blit(img0, pos)
elif game_status == GameStatus.over and mine.value:
screen.blit(img_mine, pos)
elif mine.value == 0 and mine.status == BlockStatus.flag:
screen.blit(img_error, pos)
elif mine.status == BlockStatus.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 == GameStatus.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 = GameStatus.win
if game_status == GameStatus.over:
screen.blit(img_face_fail, (face_pos_x, face_pos_y))
elif game_status == GameStatus.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()
最後說一句,CSDN 的貼程式碼看起來比部落格園爽多了,黑色背景跟 IDE 的一樣,
相關推薦
Python:遊戲:300行程式碼實現俄羅斯方塊 Python:遊戲:貪吃蛇 Python:遊戲:掃雷(附原始碼)
本文程式碼基於 python3.6 和 pygame1.9.4。 俄羅斯方塊是兒時最經典的遊戲之一,剛開始接觸 pygame 的時候就想寫一個俄羅斯方塊。但是想到旋轉,停靠,消除等操作,感覺好像很難啊,等真正寫完了發現,一共也就 300 行程式碼,並沒有什麼難的。 先來看一個遊戲截圖,有點醜,好
Python:遊戲:掃雷
這次我們基於 pygame 來做一個掃雷,上次有園友問我程式碼的 python 版本,我說明一下,我所有的程式碼都是基於 python 3.6 的。 先看截圖,仿照 XP 上的掃雷做的,感覺 XP 上的樣式比 win7 上的好看多了。 原諒我手殘,掃雷基本就沒贏過,測
Python:遊戲:測試打字速度
來看 let 測試 int 的人 time() port 輸入 style 現在寫書的人真是一點責任心都沒有,最近看了幾本書,其中的代碼都存在錯誤。 最近迷戀 Python 遊戲,買了《Python遊戲編程入門》[美] Jonathan S·Harbour 著 一書來看。
Python:遊戲:貪吃蛇(附源碼)
false 快速 寬度 技術分享 如何 game 點擊 遊戲 範圍 貪吃蛇是個非常簡單的遊戲,適合練手。 首先分析一下這個遊戲 1、蛇怎麽畫? 蛇是由一個個小方塊組成的,那麽我們可以用一個 list 記錄每一個小方塊的坐標,顯示的時候將所有小方塊畫出來即可。 2、蛇怎麽移動
Mad Libs遊戲:熟悉python編程環境,基本輸入輸出
.com inpu int 姓名 基本輸入輸出 輸入 light class pri name1=input(‘請輸入姓名‘) name2=input(‘再輸入姓名‘) print(‘{}說我就算餓死,死這裏,從6樓跳下去,也不吃同德一口飯。\n第二天,{}和{}一起在同
利用python編寫遊戲修改器!俗稱:外掛!
最近比較懷舊,在玩一個比較老的PC遊戲。由於遊戲難度太高了,於是就打算自己寫一個修改器。 通過查閱資料,在 Windows 下的修改器主要需要用到四個函式:OpenProcess, CloseHandle, WriteProcessMemory, ReadProcessMemory。 這幾個
用Python做個小遊戲:環境篇
一、安裝Python和pygame 1、在Windows環境下,安裝Python 略 2、安裝pygame,網址: http://pygame.org 使用Python自帶pip工具即可快速安裝pygame: python3 -m pip install -U py
卜若的程式碼筆記-python系列-遊戲篇-第一章:Kivy安裝以及hello world
1.安裝kivy 進入到你的python等根目錄 shift+滑鼠右鍵,喚出power shell 更新或安裝你的pip,如果已經更新完成或者安裝的請忽略 ./python -m pip install --upgrade pip 2.安裝依賴 ./pytho
Python實現簡單遊戲:飛機大戰
程式碼只寫到自己發射子彈和敵機自動發射子彈,未完待續… 裡面的飛機圖片檔案需要你們自己下載 import pygame import time from pygame.locals import * import random class plane(obj
python入門篇:開發一個簡單的猜數字小遊戲
python是史上最簡潔的語言!(其實就是一個文字遊戲) 今天太晚了,我把程式碼貼出來還有事情忙(其實是想偷個懶,不想打字,反正我有註釋) 看我的文章千萬不要著急,慢慢看完,看到最後。 ****************************** #coding=utf-8 name =
Python程式設計實現:猜數遊戲
程式設計實現:猜數遊戲 **由程式隨機產生一個0~100之間的整數,然後讓使用者輸入一個整數,判斷輸入是否正確,若正確,則結束遊戲,輸出資訊;如錯誤,則提示“大了”或“小了”,且還可再輸入一個整數,當猜數次數達到8次時,則結束遊戲。輸出資訊請按如下規則確定:
python小遊戲#石頭剪刀布遊戲:
#石頭剪刀布遊戲: import random #引入一個隨機模組 print(“1剪刀 2石頭 3布”) men=input(“請您輸入指令”) pc=random.randint(1,3) menwin_lists=[(men1 and pc3),(men2 and
Python 0基礎開發遊戲:打地鼠(詳細教程)VS code版本
如果你沒有任何程式設計經驗,而且想嘗試一下學習程式設計開發,這個系列教程一定適合你,它將帶你學習最基本的Python語法,並讓你掌握小遊戲的開發技巧。你所需要的,就是付出一些時間和耐心來嘗試這些程式碼和操作。 @[top] 一、準備工作 1 下載安裝 python 2 下載安裝VS code編輯器 安裝時
unity3D:遊戲分解之角色移動和相機跟隨
ini img form static 錄像 void 方法 lda okr 遊戲中,我們經常會有這樣的操作,點擊場景中某個位置,角色自動移動到那個位置,同時角色一直是朝向那個位置移動的,而且相機也會一直跟著角色移動。有些遊戲,鼠標滑動屏幕,相機就會圍繞角色旋
Unity3d修煉之路:遊戲開發中,3d數學知識的練習【1】(不斷更新.......)
turn tor rdo pre 長度 scrip 縮放 unity3d float #pragma strict public var m_pA : Vector3 = new Vector3(2.0f, 4.0f, 0.0f); public var m_pB :
【Unity 3D】學習筆記三十:遊戲元素——遊戲地形
nbsp 3d遊戲 strong 直觀 分辨率 == 摩擦力 fill 世界 遊戲地形 在遊戲的世界中,必然會有非常多豐富多彩的遊戲元素融合當中。它們種類繁多。作用也不大同樣。一般對於遊戲元素可分為兩種:經經常使用。不經經常使用。經常使用的元素是遊戲中比較重要的元素。一
Python簡明教程:基本概念
python1 字面意義上的常量,如2、‘This is ok‘這樣的字符串>>> print(‘a,2,3‘)a,2,32 字符串單引號(‘)使用單引號指示字符串,類似shell中的強引用,所有的空格、制表符照原樣保留。>>> print(‘This is ok‘)Thi
Python簡明教程:運算符與表達式
python Python大多數語句都包含表達式,如2+3,一個表達式可以分解為運算符和操作數。在上面的例子中,+為運算符,2和3為操作數。示例:>>> 2+35>>> 3+3*29本文出自 “一萬年太久,只爭朝夕” 博客,請務必保留此出處http://zengwj1
Python-模塊:OS,目錄及文件的簡單操作
-1 close pytho print nbsp nco 刪除目錄 os.path window 1.目錄操作 #encoding=UTF-8import unittest,osfrom time import sleep print dir(os)#獲取文件路徑‘‘‘獲
python小工具:用python操作HP的Quality Center
over cti 步驟 response headers 服務器 登錄 chm format 背景是這樣的:這個組的測試人員每跑一個case都要上傳測試結果附件到QC。每個待測功能模塊可能包含幾十上百的case。於是手工上傳測試結果變成了繁重的體力勞動。令人驚訝的是我們的工