最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python通過Pygame實(shí)現(xiàn)一個(gè)經(jīng)典掃雷游戲

 更新時(shí)間:2026年06月26日 09:13:16   作者:Wang ruoxi  
Pygame 是 Python 中一個(gè)功能強(qiáng)大的 2D 游戲開發(fā)庫,它提供了處理圖形、聲音、輸入和事件循環(huán)的完整工具集,本文通過 Pygame 實(shí)現(xiàn)一個(gè)經(jīng)典掃雷游戲項(xiàng)目,需要的朋友可以參考下

項(xiàng)目概述

Pygame 是 Python 中一個(gè)功能強(qiáng)大的 2D 游戲開發(fā)庫,它提供了處理圖形、聲音、輸入和事件循環(huán)的完整工具集。本文通過 Pygame 實(shí)現(xiàn)一個(gè)經(jīng)典掃雷游戲項(xiàng)目。

在這個(gè)游戲中,玩家需要在一個(gè)網(wǎng)格中找出所有地雷而不觸發(fā)它們。玩家點(diǎn)擊格子揭示內(nèi)容,數(shù)字表示周圍 8 個(gè)相鄰格子中地雷的數(shù)量。其中:

  • 標(biāo)記:經(jīng)典操作模式,左鍵點(diǎn)擊:揭示格子,翻開指定格子,查看內(nèi)容;右鍵點(diǎn)擊:標(biāo)記/取消標(biāo)記,對疑似地雷的格子添加或移除旗幟標(biāo)記。
  • 揭示:中鍵點(diǎn)擊:對已揭示的數(shù)字格,若周圍旗幟數(shù)=數(shù)字,自動(dòng)揭示其余格子。
  • 鍵盤操作:R:重新開始游戲;M:切換難度。
  • 勝利條件:所有「非地雷格子」都被揭示 = 游戲勝利。
  • 失敗條件:揭示了一個(gè)「地雷格子」 = 游戲失敗。
  • 首次點(diǎn)擊保護(hù):第一次點(diǎn)擊永遠(yuǎn)不會(huì)踩雷,地雷在點(diǎn)擊后動(dòng)態(tài)生成。

游戲?qū)崿F(xiàn)

初始化與基礎(chǔ)設(shè)置

在游戲啟動(dòng)前,我們需要初始化 Pygame 及其子模塊,并定義游戲所需的基礎(chǔ)參數(shù)。

# 初始化 Pygame
pygame.init()

# 難度配置:(行數(shù), 列數(shù), 地雷數(shù))
DIFFICULTIES = {
    'easy': (9, 9, 10),
    'medium': (16, 16, 40),
    'hard': (16, 30, 99)
}

# 默認(rèn)難度
CURRENT_DIFFICULTY = 'medium'
ROWS, COLS, MINE_COUNT = DIFFICULTIES[CURRENT_DIFFICULTY]

# 屏幕設(shè)置
CELL_SIZE = 30
UI_HEIGHT = 60
WIDTH = COLS * CELL_SIZE
HEIGHT = ROWS * CELL_SIZE + UI_HEIGHT
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Pygame Minesweeper")

# 顏色定義(經(jīng)典掃雷風(fēng)格)
COLORS = {
    'bg': (192, 192, 192),
    'cell': (210, 210, 210),
    'cell_revealed': (180, 180, 180),
    'border_light': (255, 255, 255),
    'border_dark': (128, 128, 128),
    'mine': (0, 0, 0),
    'flag': (255, 0, 0),
    'wrong_flag': (255, 100, 100),
    'text': {
        1: (0, 0, 255),    # 藍(lán)
        2: (0, 128, 0),    # 綠
        3: (255, 0, 0),    # 紅
        4: (0, 0, 128),    # 深藍(lán)
        5: (128, 0, 0),    # 棕
        6: (0, 128, 128),  # 青
        7: (0, 0, 0),      # 黑
        8: (128, 128, 128) # 灰
    }
}

字體加載函數(shù)

def load_safe_font(size, bold=False, italic=False):
    """加載字體"""
    try:
        return pygame.font.SysFont('arial', size, bold=bold, italic=italic)
    except (TypeError, OSError, AttributeError):
        try:
            font_dir = os.path.join(os.environ.get("WINDIR", "C:\\Windows"), "Fonts")
            font_path = os.path.join(font_dir, "arial.ttf")
            if os.path.exists(font_path):
                f = pygame.font.Font(font_path, size)
                if bold:
                    f.set_bold(True)
                if italic:
                    f.set_italic(True)
                return f
        except Exception:
            pass
        # 最終回退到默認(rèn)字體
        f = pygame.font.Font(None, size)
        if bold:
            f.set_bold(True)
        if italic:
            f.set_italic(True)
        return f

# 初始化字體
font = load_safe_font(20, bold=True)
big_font = load_safe_font(36, bold=True)
small_font = load_safe_font(16)
ui_font = load_safe_font(18)

該函數(shù)采用三級(jí)降級(jí)策略

  1. 優(yōu)先使用 SysFont 加載系統(tǒng)字體
  2. 失敗時(shí)嘗試直接讀取 Windows 字體目錄
  3. 最終回退到 pygame 內(nèi)置默認(rèn)字體

確保游戲在不同環(huán)境(Windows/Linux/macOS)和 pygame 版本下都能正常顯示文字。

游戲狀態(tài)枚舉

from enum import Enum

class GameState(Enum):
    READY = 1      # 游戲準(zhǔn)備中(首次點(diǎn)擊前)
    PLAYING = 2    # 游戲進(jìn)行中
    WON = 3        # 游戲勝利
    LOST = 4       # 游戲失敗

使用枚舉管理游戲狀態(tài),使?fàn)顟B(tài)判斷更清晰、類型更安全。

核心類設(shè)計(jì)

1. 格子類(Cell)

Cell 類封裝了掃雷中每個(gè)格子的所有狀態(tài)和行為。

構(gòu)造函數(shù) __init__

def __init__(self, row, col):
    self.row = row                    # 行索引
    self.col = col                    # 列索引
    self.is_mine = False              # 是否為地雷
    self.is_revealed = False          # 是否已被揭示
    self.is_flagged = False           # 是否被標(biāo)記為旗幟
    self.is_wrong_flag = False        # 是否錯(cuò)誤標(biāo)記(游戲結(jié)束時(shí)顯示)
    self.adjacent_mines = 0           # 周圍地雷數(shù)量(0-8)

計(jì)算周圍地雷數(shù) count_adjacent_mines

def count_adjacent_mines(self, grid):
    """計(jì)算周圍8格的地雷數(shù)量"""
    count = 0
    for dr in [-1, 0, 1]:
        for dc in [-1, 0, 1]:
            if dr == 0 and dc == 0:
                continue
            nr, nc = self.row + dr, self.col + dc
            if 0 <= nr < len(grid) and 0 <= nc < len(grid[0]):
                if grid[nr][nc].is_mine:
                    count += 1
    self.adjacent_mines = count

遍歷周圍 8 個(gè)方向,統(tǒng)計(jì)地雷數(shù)量并存儲(chǔ)。

揭示格子 reveal

def reveal(self):
    """揭示格子"""
    if self.is_revealed or self.is_flagged:
        return
    self.is_revealed = True

標(biāo)記格子為已揭示,并避免重復(fù)操作。

繪制方法 draw

def draw(self, surface, cell_size, offset_x, offset_y, game_state):
    x = offset_x + self.col * cell_size
    y = offset_y + self.row * cell_size
    
    # 繪制格子背景(3D邊框效果)
    if self.is_revealed:
        pygame.draw.rect(surface, COLORS['cell_revealed'], 
                        (x, y, cell_size, cell_size))
    else:
        pygame.draw.rect(surface, COLORS['cell'], 
                        (x, y, cell_size, cell_size))
        # 繪制亮/暗邊框營造立體感
        pygame.draw.line(surface, COLORS['border_light'], (x, y), (x + cell_size, y), 2)
        pygame.draw.line(surface, COLORS['border_light'], (x, y), (x, y + cell_size), 2)
        pygame.draw.line(surface, COLORS['border_dark'], (x + cell_size, y), (x + cell_size, y + cell_size), 2)
        pygame.draw.line(surface, COLORS['border_dark'], (x, y + cell_size), (x + cell_size, y + cell_size), 2)
    
    # 繪制內(nèi)容:地雷/數(shù)字/旗幟
    if self.is_revealed:
        if self.is_mine:
            # 繪制地雷(圓形+十字)
            cx, cy = x + cell_size//2, y + cell_size//2
            pygame.draw.circle(surface, COLORS['mine'], (cx, cy), cell_size//3)
            pygame.draw.line(surface, COLORS['flag'], (cx-8, cy-8), (cx+8, cy+8), 2)
            pygame.draw.line(surface, COLORS['flag'], (cx+8, cy-8), (cx-8, cy+8), 2)
        elif self.adjacent_mines > 0:
            color = COLORS['text'].get(self.adjacent_mines, (0, 0, 0))
            text = font.render(str(self.adjacent_mines), True, color)
            text_rect = text.get_rect(center=(x + cell_size//2, y + cell_size//2))
            surface.blit(text, text_rect)
    elif self.is_flagged:
        # 繪制旗幟(旗桿+旗面)
        color = COLORS['wrong_flag'] if (self.is_wrong_flag and game_state == GameState.LOST) else COLORS['flag']
        pygame.draw.line(surface, (100, 100, 100), 
                        (x + cell_size//3, y + cell_size//4), 
                        (x + cell_size//3, y + 3*cell_size//4), 2)
        pygame.draw.polygon(surface, color, [
            (x + cell_size//3, y + cell_size//4),
            (x + cell_size//3 + 12, y + cell_size//3),
            (x + cell_size//3, y + cell_size//2 - 2)
        ])

2. 游戲主類(MineSweeperGame)

MineSweeperGame 類是整個(gè)游戲的控制中心,負(fù)責(zé)初始化、狀態(tài)管理、事件處理、邏輯更新和渲染。

構(gòu)造函數(shù) __init__

def __init__(self, rows=16, cols=16, mines=40):
    self.rows = rows
    self.cols = cols
    self.mine_count = mines
    self.cell_size = CELL_SIZE
    self.offset_x = 0
    self.offset_y = UI_HEIGHT
    
    self.grid = []           # 格子二維數(shù)組
    self.first_click = True  # 是否首次點(diǎn)擊(用于保證首次安全)
    self.state = GameState.READY
    self.start_time = None
    self.elapsed_time = 0
    self.flags_placed = 0
    
    self.create_grid()

創(chuàng)建網(wǎng)格 create_grid

def create_grid(self):
    """創(chuàng)建空白網(wǎng)格"""
    self.grid = []
    for r in range(self.rows):
        row = [Cell(r, c) for c in range(self.cols)]
        self.grid.append(row)

生成地雷 place_mines

def place_mines(self, exclude_row, exclude_col):
    """排除首次點(diǎn)擊位置后隨機(jī)放置地雷"""
    positions = [(r, c) for r in range(self.rows) for c in range(self.cols) 
                 if not (r == exclude_row and c == exclude_col)]
    mine_positions = random.sample(positions, self.mine_count)
    
    for r, c in mine_positions:
        self.grid[r][c].is_mine = True
    
    # 計(jì)算每個(gè)格子的相鄰地雷數(shù)
    for row in self.grid:
        for cell in row:
            cell.count_adjacent_mines(self.grid)

擴(kuò)散算法 flood_fill

def flood_fill(self, start_row, start_col):
    """BFS擴(kuò)散揭示空白區(qū)域:揭示所有相連的空白格+邊緣數(shù)字格"""
    queue = deque([(start_row, start_col)])
    visited = set()
    
    while queue:
        r, c = queue.popleft()
        if (r, c) in visited:
            continue
        visited.add((r, c))
        
        cell = self.grid[r][c]
        
        # 只跳過被標(biāo)記的格子,允許已揭示的格子繼續(xù)擴(kuò)散
        if cell.is_flagged:
            continue
        
        # 揭示當(dāng)前格子(如果已揭示,reveal() 會(huì)直接返回,無副作用)
        cell.reveal()
        
        # 只有空白格子(相鄰地雷數(shù)=0)才繼續(xù)擴(kuò)散周圍
        if cell.adjacent_mines == 0 and not cell.is_mine:
            for dr in [-1, 0, 1]:
                for dc in [-1, 0, 1]:
                    if dr == 0 and dc == 0:
                        continue
                    nr, nc = r + dr, c + dc
                    if 0 <= nr < self.rows and 0 <= nc < self.cols:
                        neighbor = self.grid[nr][nc]
                        # 只將未揭示且未標(biāo)記的鄰居加入隊(duì)列
                        if not neighbor.is_revealed and not neighbor.is_flagged:
                            queue.append((nr, nc))

檢查勝利條件 check_win

def check_win(self):
    """檢查是否所有非地雷格子都被揭示"""
    for row in self.grid:
        for cell in row:
            if not cell.is_mine and not cell.is_revealed:
                return False
    return True

快速揭示 chord_reveal

def chord_reveal(self, row, col):
    """雙擊已揭示數(shù)字:若旗幟數(shù)=數(shù)字,揭示其余格子"""
    cell = self.grid[row][col]
    if not cell.is_revealed or cell.adjacent_mines == 0:
        return
    
    flag_count = 0
    to_reveal = []
    
    for dr in [-1, 0, 1]:
        for dc in [-1, 0, 1]:
            if dr == 0 and dc == 0:
                continue
            nr, nc = row + dr, col + dc
            if 0 <= nr < self.rows and 0 <= nc < self.cols:
                neighbor = self.grid[nr][nc]
                if neighbor.is_flagged:
                    flag_count += 1
                elif not neighbor.is_revealed:
                    to_reveal.append((nr, nc))
    
    if flag_count == cell.adjacent_mines:
        for nr, nc in to_reveal:
            target = self.grid[nr][nc]
            if target.is_mine:
                self.state = GameState.LOST
                self.reveal_all_mines()
                return
            target.reveal()
            if target.adjacent_mines == 0 and not target.is_mine:
                self.flood_fill(nr, nc)
        if self.check_win():
            self.state = GameState.WON
            self.mark_correct_flags()

事件處理方法 handle_events

def handle_events(self):
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            return False
        
        if event.type == pygame.MOUSEBUTTONDOWN:
            if self.state in [GameState.READY, GameState.PLAYING]:
                mx, my = pygame.mouse.get_pos()
                col = (mx - self.offset_x) // self.cell_size
                row = (my - self.offset_y) // self.cell_size
                
                if 0 <= row < self.rows and 0 <= col < self.cols:
                    cell = self.grid[row][col]
                    
                    # 左鍵:揭示
                    if event.button == 1 and not cell.is_flagged:
                        if self.first_click:
                            self.first_click = False
                            self.place_mines(row, col)
                            self.start_time = pygame.time.get_ticks()
                            self.state = GameState.PLAYING
                        
                        if cell.is_mine:
                            self.state = GameState.LOST
                            self.reveal_all_mines()
                        else:
                            # 先揭示起始格子
                            cell.reveal()
                            # 如果是空白格,觸發(fā)擴(kuò)散
                            if cell.adjacent_mines == 0:
                                self.flood_fill(row, col)
                            # 檢查勝利
                            if self.check_win():
                                self.state = GameState.WON
                                self.mark_correct_flags()
                    
                    # 右鍵:標(biāo)記旗幟
                    elif event.button == 3 and not cell.is_revealed:
                        if cell.is_flagged:
                            cell.is_flagged = False
                            self.flags_placed -= 1
                        else:
                            cell.is_flagged = True
                            self.flags_placed += 1
                    
                    # 中鍵 或 Ctrl+左鍵:快速揭示
                    elif (event.button == 2 or 
                          (event.button == 1 and pygame.key.get_mods() & pygame.KMOD_CTRL)):
                        if cell.is_revealed and cell.adjacent_mines > 0:
                            self.chord_reveal(row, col)
        
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_r:      # R: 重開
                self.__init__(self.rows, self.cols, self.mine_count)
            elif event.key == pygame.K_m:    # M: 切換難度
                self.change_difficulty()
            elif event.key == pygame.K_ESCAPE:  # ESC: 退出
                return False
    
    return True

繪制方法 draw

def draw(self):
    screen.fill(COLORS['bg'])
    
    # 繪制所有格子
    for row in self.grid:
        for cell in row:
            cell.draw(screen, self.cell_size, self.offset_x, self.offset_y, self.state)
    
    # 繪制頂部信息欄
    self.draw_ui()
    
    # 游戲狀態(tài)遮罩
    if self.state == GameState.WON:
        self.draw_overlay("VICTORY!", "Time: " + str(self.elapsed_time) + "s",
                         (100, 255, 100), (200, 255, 200))
    elif self.state == GameState.LOST:
        self.draw_overlay("BOOM!", "Better luck next time!",
                         (255, 100, 100), (255, 200, 200))
    
    pygame.display.flip()

主循環(huán)方法 run

def run(self):
    clock = pygame.time.Clock()
    running = True
    while running:
        running = self.handle_events()
        self.draw()
        clock.tick(60)
    
    pygame.quit()
    sys.exit()

全部代碼

import pygame
import random
import sys
import os
from enum import Enum
from collections import deque

# ==================== 初始化配置 ====================
pygame.init()

# 難度配置:(行數(shù), 列數(shù), 地雷數(shù))
DIFFICULTIES = {
    'easy': (9, 9, 10),
    'medium': (16, 16, 40),
    'hard': (16, 30, 99)
}

# 默認(rèn)難度
CURRENT_DIFFICULTY = 'medium'
ROWS, COLS, MINE_COUNT = DIFFICULTIES[CURRENT_DIFFICULTY]

CELL_SIZE = 30
UI_HEIGHT = 60
WIDTH = COLS * CELL_SIZE
HEIGHT = ROWS * CELL_SIZE + UI_HEIGHT

screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Pygame Minesweeper")

# 顏色定義(經(jīng)典掃雷風(fēng)格)
COLORS = {
    'bg': (192, 192, 192),
    'cell': (210, 210, 210),
    'cell_revealed': (180, 180, 180),
    'border_light': (255, 255, 255),
    'border_dark': (128, 128, 128),
    'mine': (0, 0, 0),
    'flag': (255, 0, 0),
    'wrong_flag': (255, 100, 100),
    'text': {
        1: (0, 0, 255),  # Blue
        2: (0, 128, 0),  # Green
        3: (255, 0, 0),  # Red
        4: (0, 0, 128),  # Dark Blue
        5: (128, 0, 0),  # Brown
        6: (0, 128, 128),  # Teal
        7: (0, 0, 0),  # Black
        8: (128, 128, 128)  # Gray
    }
}


# ==================== 字體加載函數(shù) ====================
def load_safe_font(size, bold=False, italic=False):
    """安全加載字體,修復(fù) pygame 2.6+ 字體初始化 bug"""
    try:
        return pygame.font.SysFont('arial', size, bold=bold, italic=italic)
    except (TypeError, OSError, AttributeError):
        try:
            font_dir = os.path.join(os.environ.get("WINDIR", "C:\\Windows"), "Fonts")
            font_path = os.path.join(font_dir, "arial.ttf")
            if os.path.exists(font_path):
                f = pygame.font.Font(font_path, size)
                if bold:
                    f.set_bold(True)
                if italic:
                    f.set_italic(True)
                return f
        except Exception:
            pass
        f = pygame.font.Font(None, size)
        if bold:
            f.set_bold(True)
        if italic:
            f.set_italic(True)
        return f


# 初始化字體
font = load_safe_font(20, bold=True)
big_font = load_safe_font(36, bold=True)
small_font = load_safe_font(16)
ui_font = load_safe_font(18)


# ==================== 游戲狀態(tài)枚舉 ====================
class GameState(Enum):
    READY = 1
    PLAYING = 2
    WON = 3
    LOST = 4


# ==================== 格子類 ====================
class Cell:
    def __init__(self, row, col):
        self.row = row
        self.col = col
        self.is_mine = False
        self.is_revealed = False
        self.is_flagged = False
        self.is_wrong_flag = False
        self.adjacent_mines = 0

    def count_adjacent_mines(self, grid):
        """計(jì)算周圍8格的地雷數(shù)量"""
        count = 0
        for dr in [-1, 0, 1]:
            for dc in [-1, 0, 1]:
                if dr == 0 and dc == 0:
                    continue
                nr, nc = self.row + dr, self.col + dc
                if 0 <= nr < len(grid) and 0 <= nc < len(grid[0]):
                    if grid[nr][nc].is_mine:
                        count += 1
        self.adjacent_mines = count

    def reveal(self):
        """揭示格子"""
        if self.is_revealed or self.is_flagged:
            return
        self.is_revealed = True

    def draw(self, surface, cell_size, offset_x, offset_y, game_state):
        x = offset_x + self.col * cell_size
        y = offset_y + self.row * cell_size

        # 繪制格子背景
        if self.is_revealed:
            pygame.draw.rect(surface, COLORS['cell_revealed'],
                             (x, y, cell_size, cell_size))
        else:
            pygame.draw.rect(surface, COLORS['cell'],
                             (x, y, cell_size, cell_size))
            pygame.draw.line(surface, COLORS['border_light'],
                             (x, y), (x + cell_size, y), 2)
            pygame.draw.line(surface, COLORS['border_light'],
                             (x, y), (x, y + cell_size), 2)
            pygame.draw.line(surface, COLORS['border_dark'],
                             (x + cell_size, y), (x + cell_size, y + cell_size), 2)
            pygame.draw.line(surface, COLORS['border_dark'],
                             (x, y + cell_size), (x + cell_size, y + cell_size), 2)

        # 繪制內(nèi)容
        if self.is_revealed:
            if self.is_mine:
                cx, cy = x + cell_size // 2, y + cell_size // 2
                pygame.draw.circle(surface, COLORS['mine'], (cx, cy), cell_size // 3)
                pygame.draw.line(surface, COLORS['flag'], (cx - 8, cy - 8), (cx + 8, cy + 8), 2)
                pygame.draw.line(surface, COLORS['flag'], (cx + 8, cy - 8), (cx - 8, cy + 8), 2)
            elif self.adjacent_mines > 0:
                color = COLORS['text'].get(self.adjacent_mines, (0, 0, 0))
                text = font.render(str(self.adjacent_mines), True, color)
                text_rect = text.get_rect(center=(x + cell_size // 2, y + cell_size // 2))
                surface.blit(text, text_rect)
        elif self.is_flagged:
            color = COLORS['wrong_flag'] if (self.is_wrong_flag and game_state == GameState.LOST) else COLORS['flag']
            pygame.draw.line(surface, (100, 100, 100),
                             (x + cell_size // 3, y + cell_size // 4),
                             (x + cell_size // 3, y + 3 * cell_size // 4), 2)
            pygame.draw.polygon(surface, color, [
                (x + cell_size // 3, y + cell_size // 4),
                (x + cell_size // 3 + 12, y + cell_size // 3),
                (x + cell_size // 3, y + cell_size // 2 - 2)
            ])


# ==================== 游戲主類 ====================
class MineSweeperGame:
    def __init__(self, rows=16, cols=16, mines=40):
        self.rows = rows
        self.cols = cols
        self.mine_count = mines
        self.cell_size = CELL_SIZE
        self.offset_x = 0
        self.offset_y = UI_HEIGHT

        self.grid = []
        self.first_click = True
        self.state = GameState.READY
        self.start_time = None
        self.elapsed_time = 0
        self.flags_placed = 0

        self.create_grid()

    def create_grid(self):
        """創(chuàng)建空白網(wǎng)格"""
        self.grid = []
        for r in range(self.rows):
            row = [Cell(r, c) for c in range(self.cols)]
            self.grid.append(row)

    def place_mines(self, exclude_row, exclude_col):
        """排除首次點(diǎn)擊位置后隨機(jī)放置地雷"""
        positions = [(r, c) for r in range(self.rows) for c in range(self.cols)
                     if not (r == exclude_row and c == exclude_col)]
        mine_positions = random.sample(positions, self.mine_count)

        for r, c in mine_positions:
            self.grid[r][c].is_mine = True

        for row in self.grid:
            for cell in row:
                cell.count_adjacent_mines(self.grid)

    def flood_fill(self, start_row, start_col):
        """BFS擴(kuò)散揭示空白區(qū)域:揭示所有相連的空白格+邊緣數(shù)字格"""
        queue = deque([(start_row, start_col)])
        visited = set()

        while queue:
            r, c = queue.popleft()
            if (r, c) in visited:
                continue
            visited.add((r, c))

            cell = self.grid[r][c]

            # 只跳過被標(biāo)記的格子,允許已揭示的格子繼續(xù)擴(kuò)散
            if cell.is_flagged:
                continue

            # 揭示當(dāng)前格子(如果已揭示,reveal() 會(huì)直接返回,無副作用)
            cell.reveal()

            # 只有空白格子(相鄰地雷數(shù)=0)才繼續(xù)擴(kuò)散周圍
            if cell.adjacent_mines == 0 and not cell.is_mine:
                for dr in [-1, 0, 1]:
                    for dc in [-1, 0, 1]:
                        if dr == 0 and dc == 0:
                            continue
                        nr, nc = r + dr, c + dc
                        if 0 <= nr < self.rows and 0 <= nc < self.cols:
                            neighbor = self.grid[nr][nc]
                            # 只將未揭示且未標(biāo)記的鄰居加入隊(duì)列
                            if not neighbor.is_revealed and not neighbor.is_flagged:
                                queue.append((nr, nc))

    def check_win(self):
        """檢查是否所有非地雷格子都被揭示"""
        for row in self.grid:
            for cell in row:
                if not cell.is_mine and not cell.is_revealed:
                    return False
        return True

    def reveal_all_mines(self):
        """游戲失敗時(shí)揭示所有地雷"""
        for row in self.grid:
            for cell in row:
                if cell.is_mine:
                    cell.is_revealed = True
                elif cell.is_flagged and not cell.is_mine:
                    cell.is_wrong_flag = True

    def mark_correct_flags(self):
        """游戲勝利時(shí)自動(dòng)標(biāo)記剩余地雷"""
        for row in self.grid:
            for cell in row:
                if cell.is_mine and not cell.is_flagged:
                    cell.is_flagged = True

    def chord_reveal(self, row, col):
        """雙擊已揭示數(shù)字:若旗幟數(shù)=數(shù)字,揭示其余格子"""
        cell = self.grid[row][col]
        if not cell.is_revealed or cell.adjacent_mines == 0:
            return

        flag_count = 0
        to_reveal = []

        for dr in [-1, 0, 1]:
            for dc in [-1, 0, 1]:
                if dr == 0 and dc == 0:
                    continue
                nr, nc = row + dr, col + dc
                if 0 <= nr < self.rows and 0 <= nc < self.cols:
                    neighbor = self.grid[nr][nc]
                    if neighbor.is_flagged:
                        flag_count += 1
                    elif not neighbor.is_revealed:
                        to_reveal.append((nr, nc))

        if flag_count == cell.adjacent_mines:
            for nr, nc in to_reveal:
                target = self.grid[nr][nc]
                if target.is_mine:
                    self.state = GameState.LOST
                    self.reveal_all_mines()
                    return
                target.reveal()
                if target.adjacent_mines == 0 and not target.is_mine:
                    self.flood_fill(nr, nc)
            if self.check_win():
                self.state = GameState.WON
                self.mark_correct_flags()

    def draw_ui(self):
        """繪制頂部信息欄"""
        pygame.draw.rect(screen, (80, 80, 90), (0, 0, WIDTH, UI_HEIGHT))
        pygame.draw.line(screen, (255, 255, 255), (0, UI_HEIGHT), (WIDTH, UI_HEIGHT), 2)

        if self.start_time and self.state == GameState.PLAYING:
            self.elapsed_time = (pygame.time.get_ticks() - self.start_time) // 1000

        time_text = ui_font.render("Time: " + str(self.elapsed_time) + "s", True, (255, 255, 255))
        screen.blit(time_text, (10, 20))

        remaining = max(0, self.mine_count - self.flags_placed)
        mine_text = ui_font.render("Mines: " + str(remaining), True, (255, 80, 80))
        mine_width = mine_text.get_width()
        screen.blit(mine_text, (WIDTH - mine_width - 10, 20))

        diff_text = ui_font.render("[" + CURRENT_DIFFICULTY.upper() + "]", True, (150, 200, 255))
        diff_width = diff_text.get_width()
        screen.blit(diff_text, (WIDTH // 2 - diff_width // 2, 20))

        if self.state == GameState.READY:
            status = ui_font.render("Click to Start", True, (200, 200, 200))
        elif self.state == GameState.PLAYING:
            status = ui_font.render("Good Luck!", True, (150, 255, 150))
        elif self.state == GameState.WON:
            status = ui_font.render("YOU WIN!", True, (100, 255, 100))
        else:
            status = ui_font.render("GAME OVER", True, (255, 100, 100))

        status_width = status.get_width()
        screen.blit(status, (WIDTH // 2 - status_width // 2, 40))

    def draw_overlay(self, title, subtitle, title_color, subtitle_color):
        """繪制游戲結(jié)束遮罩"""
        overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
        overlay.fill((0, 0, 0, 160))
        screen.blit(overlay, (0, 0))

        title_surf = big_font.render(title, True, title_color)
        subtitle_surf = font.render(subtitle, True, subtitle_color)
        hint_surf = ui_font.render("Press [R] Restart | [M] Change Difficulty", True, (200, 200, 200))

        screen.blit(title_surf, (WIDTH // 2 - title_surf.get_width() // 2, HEIGHT // 2 - 60))
        screen.blit(subtitle_surf, (WIDTH // 2 - subtitle_surf.get_width() // 2, HEIGHT // 2 - 10))
        screen.blit(hint_surf, (WIDTH // 2 - hint_surf.get_width() // 2, HEIGHT // 2 + 40))

    def change_difficulty(self):
        """循環(huán)切換難度"""
        global CURRENT_DIFFICULTY, ROWS, COLS, MINE_COUNT
        diff_list = list(DIFFICULTIES.keys())
        idx = diff_list.index(CURRENT_DIFFICULTY)
        CURRENT_DIFFICULTY = diff_list[(idx + 1) % len(diff_list)]
        ROWS, COLS, MINE_COUNT = DIFFICULTIES[CURRENT_DIFFICULTY]
        self.__init__(ROWS, COLS, MINE_COUNT)

    def handle_events(self):
        """處理輸入事件"""
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                return False

            if event.type == pygame.MOUSEBUTTONDOWN:
                if self.state in [GameState.READY, GameState.PLAYING]:
                    mx, my = pygame.mouse.get_pos()
                    col = (mx - self.offset_x) // self.cell_size
                    row = (my - self.offset_y) // self.cell_size

                    if 0 <= row < self.rows and 0 <= col < self.cols:
                        cell = self.grid[row][col]

                        # 左鍵:揭示
                        if event.button == 1 and not cell.is_flagged:
                            if self.first_click:
                                self.first_click = False
                                self.place_mines(row, col)
                                self.start_time = pygame.time.get_ticks()
                                self.state = GameState.PLAYING

                            if cell.is_mine:
                                self.state = GameState.LOST
                                self.reveal_all_mines()
                            else:
                                # 先揭示起始格子
                                cell.reveal()
                                # 如果是空白格,觸發(fā)擴(kuò)散
                                if cell.adjacent_mines == 0:
                                    self.flood_fill(row, col)
                                # 檢查勝利
                                if self.check_win():
                                    self.state = GameState.WON
                                    self.mark_correct_flags()

                        # 右鍵:標(biāo)記旗幟
                        elif event.button == 3 and not cell.is_revealed:
                            if cell.is_flagged:
                                cell.is_flagged = False
                                self.flags_placed -= 1
                            else:
                                cell.is_flagged = True
                                self.flags_placed += 1

                        # 中鍵:快速揭示
                        elif event.button == 2:
                            if cell.is_revealed and cell.adjacent_mines > 0:
                                self.chord_reveal(row, col)

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_r:
                    self.__init__(self.rows, self.cols, self.mine_count)
                elif event.key == pygame.K_m:
                    self.change_difficulty()
                elif event.key == pygame.K_ESCAPE:
                    return False

        return True

    def draw(self):
        """繪制整個(gè)游戲畫面"""
        screen.fill(COLORS['bg'])

        for row in self.grid:
            for cell in row:
                cell.draw(screen, self.cell_size, self.offset_x, self.offset_y, self.state)

        self.draw_ui()

        if self.state == GameState.WON:
            self.draw_overlay("VICTORY!", "Time: " + str(self.elapsed_time) + "s",
                              (100, 255, 100), (200, 255, 200))
        elif self.state == GameState.LOST:
            self.draw_overlay("BOOM!", "Better luck next time!",
                              (255, 100, 100), (255, 200, 200))

        pygame.display.flip()

    def run(self):
        """游戲主循環(huán)"""
        clock = pygame.time.Clock()
        running = True
        while running:
            running = self.handle_events()
            self.draw()
            clock.tick(60)

        pygame.quit()
        sys.exit()


# ==================== 程序入口 ====================
if __name__ == "__main__":
    print("Pygame Minesweeper - Classic Edition")
    print("Controls:")
    print("  Left Click  : Reveal cell")
    print("  Right Click : Place/Remove flag")
    print("  Middle Click / Ctrl+Left: Quick reveal around number")
    print("  [R]  : Restart game")
    print("  [M]  : Change difficulty (Easy/Medium/Hard)")
    print("  [ESC]: Exit")
    print("-" * 40)

    game = MineSweeperGame(ROWS, COLS, MINE_COUNT)
    game.run()

以上就是Python通過Pygame實(shí)現(xiàn)一個(gè)經(jīng)典掃雷游戲的詳細(xì)內(nèi)容,更多關(guān)于Python Pygame掃雷游戲的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Python基于scipy實(shí)現(xiàn)信號(hào)濾波功能

    Python基于scipy實(shí)現(xiàn)信號(hào)濾波功能

    本文將以實(shí)戰(zhàn)的形式基于scipy模塊使用Python實(shí)現(xiàn)簡單濾波處理。這篇文章主要介紹了Python基于scipy實(shí)現(xiàn)信號(hào)濾波功能,需要的朋友可以參考下
    2019-05-05
  • python異常處理try的實(shí)例小結(jié)

    python異常處理try的實(shí)例小結(jié)

    python提供了兩個(gè)非常重要的功能來處理python程序在運(yùn)行中出現(xiàn)的異常和錯(cuò)誤。你可以使用該功能來調(diào)試python程序。今天通過本文給大家介紹python異常處理try的實(shí)例詳解,感興趣的朋友一起看看吧
    2021-10-10
  • python字典按照value排序方法

    python字典按照value排序方法

    在本篇文章里小編給各位分享一篇關(guān)于python字典按照value排序方法的相關(guān)文章,有興趣的朋友們可以學(xué)習(xí)下。
    2020-12-12
  • python實(shí)現(xiàn)無邊框進(jìn)度條的實(shí)例代碼

    python實(shí)現(xiàn)無邊框進(jìn)度條的實(shí)例代碼

    這篇文章主要介紹了python實(shí)現(xiàn)無邊框進(jìn)度條的實(shí)例代碼,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-12-12
  • 理解python中裝飾器的作用

    理解python中裝飾器的作用

    python裝飾器就是用于拓展原來函數(shù)功能的一種函數(shù),這個(gè)函數(shù)的特殊之處在于它的返回值也是一個(gè)函數(shù),使用python裝飾器的好處就是在不用更改原函數(shù)的代碼前提下給函數(shù)增加新的功能
    2021-07-07
  • Selenium+BeautifulSoup+json獲取Script標(biāo)簽內(nèi)的json數(shù)據(jù)

    Selenium+BeautifulSoup+json獲取Script標(biāo)簽內(nèi)的json數(shù)據(jù)

    這篇文章主要介紹了Selenium+BeautifulSoup+json獲取Script標(biāo)簽內(nèi)的json數(shù)據(jù),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • python算的上腳本語言嗎

    python算的上腳本語言嗎

    在本篇內(nèi)容中小編給大家分享的是關(guān)于python是否屬于腳本語言的相關(guān)內(nèi)容知識(shí)點(diǎn),有興趣的朋友們可以參考下。
    2020-06-06
  • Python函數(shù)式編程指南(二):從函數(shù)開始

    Python函數(shù)式編程指南(二):從函數(shù)開始

    這篇文章主要介紹了Python函數(shù)式編程指南(二):從函數(shù)開始,本文講解了定義一個(gè)函數(shù)、使用函數(shù)賦值、閉包、作為參數(shù)等內(nèi)容,需要的朋友可以參考下
    2015-06-06
  • HTTPX入門使用教程

    HTTPX入門使用教程

    HTTPX是一款Python棧HTTP客戶端庫,它提供了比標(biāo)準(zhǔn)庫更高級(jí)別、更先進(jìn)的功能,如連接重用、連接池、超時(shí)控制、自動(dòng)繁衍請求,下面通過本文介紹HTTPX入門知識(shí)和基本用法,感興趣的朋友一起看看吧
    2023-12-12
  • python畫出三角形外接圓和內(nèi)切圓的方法

    python畫出三角形外接圓和內(nèi)切圓的方法

    這篇文章主要為大家詳細(xì)介紹了python畫出三角形外接圓和內(nèi)切圓的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-01-01

最新評論

射洪县| 南昌市| 鲁山县| 合川市| 屏东县| 晋宁县| 合阳县| 朝阳区| 石楼县| 宝清县| 鄂伦春自治旗| 云霄县| 确山县| 六安市| 东乡县| 岳西县| 梨树县| 北京市| 汝州市| 微博| 宜阳县| 酉阳| 祥云县| 南溪县| 德兴市| 阿勒泰市| 大理市| 新丰县| 富阳市| 奎屯市| 白玉县| 太仓市| 彰化市| 红安县| 房山区| 沛县| 冕宁县| 望都县| 温泉县| 隆化县| 无锡市|