扫雷

`import pygame
import random
import sys
from typing import List, Tuple, Optional

初始化pygame

pygame.init()

确保中文显示正常

pygame.font.init()
font_path = pygame.font.match_font('simsun') or pygame.font.match_font('microsoftyahei')
if not font_path:
# 如果找不到中文字体,使用默认字体
font_path = pygame.font.get_default_font()

class Cell:
"""扫雷游戏中的单个格子"""
def init(self, x: int, y: int):
self.x = x
self.y = y
self.is_mine = False
self.is_revealed = False
self.is_flagged = False
self.adjacent_mines = 0

def toggle_flag(self) -> None:
    """切换旗帜状态"""
    if not self.is_revealed:
        self.is_flagged = not self.is_flagged

def reveal(self) -> bool:
    """翻开格子,返回是否是地雷"""
    if self.is_revealed or self.is_flagged:
        return False
    
    self.is_revealed = True
    return self.is_mine

class Minesweeper:
"""扫雷游戏主类"""
def init(self, width: int = 10, height: int = 10, mines: int = 10):
self.width = width
self.height = height
self.mines = mines
self.board = [[Cell(x, y) for y in range(height)] for x in range(width)]
self.game_over = False
self.victory = False
self.first_click = True
self.revealed_cells = 0
self.flags_placed = 0
self.start_time = 0
self.elapsed_time = 0
self.clock = pygame.time.Clock()

    # 设置窗口
    self.cell_size = 30
    self.header_height = 100
    self.screen_width = width * self.cell_size
    self.screen_height = height * self.cell_size + self.header_height
    self.screen = pygame.display.set_mode((self.screen_width, self.screen_height))
    pygame.display.set_caption("扫雷游戏")
    
    # 加载字体
    self.font_large = pygame.font.Font(font_path, 36)
    self.font_small = pygame.font.Font(font_path, 24)
    
    # 颜色定义
    self.COLORS = {
        'BACKGROUND': (200, 200, 200),
        'GRID': (100, 100, 100),
        'CELL_HIDDEN': (180, 180, 180),
        'CELL_REVEALED': (230, 230, 230),
        'MINE': (255, 0, 0),
        'FLAG': (255, 0, 0),
        'TEXT': (0, 0, 0),
        'HEADER': (150, 150, 150),
        'NUMBER_1': (0, 0, 255),
        'NUMBER_2': (0, 128, 0),
        'NUMBER_3': (255, 0, 0),
        'NUMBER_4': (0, 0, 128),
        'NUMBER_5': (128, 0, 0),
        'NUMBER_6': (0, 128, 128),
        'NUMBER_7': (0, 0, 0),
        'NUMBER_8': (128, 128, 128),
    }
    
    # 按钮设置
    self.reset_button = pygame.Rect(
        self.screen_width // 2 - 30, 
        self.header_height // 2 - 15, 
        60, 
        30
    )

def initialize_board(self, first_x: int, first_y: int) -> None:
    """初始化游戏棋盘,确保第一次点击不是地雷"""
    # 放置地雷
    mines_placed = 0
    while mines_placed < self.mines:
        x = random.randint(0, self.width - 1)
        y = random.randint(0, self.height - 1)
        
        # 确保不在第一次点击的位置及其相邻位置放置地雷
        if (x == first_x and y == first_y) or \
           (abs(x - first_x) <= 1 and abs(y - first_y) <= 1):
            continue
            
        if not self.board[x][y].is_mine:
            self.board[x][y].is_mine = True
            mines_placed += 1
    
    # 计算每个格子周围的地雷数
    for x in range(self.width):
        for y in range(self.height):
            if not self.board[x][y].is_mine:
                self.board[x][y].adjacent_mines = self.count_adjacent_mines(x, y)

def count_adjacent_mines(self, x: int, y: int) -> int:
    """计算指定格子周围的地雷数量"""
    count = 0
    for dx in [-1, 0, 1]:
        for dy in [-1, 0, 1]:
            if dx == 0 and dy == 0:
                continue
                
            nx, ny = x + dx, y + dy
            if 0 <= nx < self.width and 0 <= ny < self.height:
                if self.board[nx][ny].is_mine:
                    count += 1
    return count

def reveal_empty_cells(self, x: int, y: int) -> None:
    """递归翻开所有相邻的空格子"""
    if self.board[x][y].adjacent_mines != 0:
        return
        
    for dx in [-1, 0, 1]:
        for dy in [-1, 0, 1]:
            if dx == 0 and dy == 0:
                continue
                
            nx, ny = x + dx, y + dy
            if 0 <= nx < self.width and 0 <= ny < self.height:
                cell = self.board[nx][ny]
                if not cell.is_revealed and not cell.is_flagged:
                    cell.reveal()
                    self.revealed_cells += 1
                    if cell.adjacent_mines == 0:
                        self.reveal_empty_cells(nx, ny)

def check_victory(self) -> bool:
    """检查游戏是否胜利"""
    # 胜利条件:所有非地雷格子都被翻开
    return self.revealed_cells == self.width * self.height - self.mines

def handle_click(self, x: int, y: int, button: int) -> None:
    """处理鼠标点击事件"""
    if self.game_over or self.victory:
        return
        
    # 转换为格子坐标
    grid_x = x // self.cell_size
    grid_y = (y - self.header_height) // self.cell_size
    
    if grid_y < 0 or grid_x >= self.width or grid_y >= self.height:
        return
        
    cell = self.board[grid_x][grid_y]
    
    if button == 1:  # 左键点击
        if self.first_click:
            self.first_click = False
            self.initialize_board(grid_x, grid_y)
            self.start_time = pygame.time.get_ticks()
            
        if cell.is_flagged:
            return
            
        if cell.reveal():
            self.game_over = True
            return
            
        self.revealed_cells += 1
        
        if cell.adjacent_mines == 0:
            self.reveal_empty_cells(grid_x, grid_y)
            
        self.victory = self.check_victory()
        
    elif button == 3:  # 右键点击
        if self.first_click:
            return
            
        if not cell.is_revealed:
            cell.toggle_flag()
            if cell.is_flagged:
                self.flags_placed += 1
            else:
                self.flags_placed -= 1
                
            self.victory = self.check_victory()

def draw_cell(self, cell: Cell) -> None:
    """绘制单个格子"""
    rect = pygame.Rect(
        cell.x * self.cell_size,
        self.header_height + cell.y * self.cell_size,
        self.cell_size,
        self.cell_size
    )
    
    # 绘制格子背景
    if cell.is_revealed:
        pygame.draw.rect(self.screen, self.COLORS['CELL_REVEALED'], rect)
        pygame.draw.rect(self.screen, self.COLORS['GRID'], rect, 1)
        
        # 如果是地雷
        if cell.is_mine:
            pygame.draw.circle(
                self.screen, 
                self.COLORS['MINE'], 
                (rect.centerx, rect.centery), 
                self.cell_size // 3
            )
        # 如果周围有地雷,显示数字
        elif cell.adjacent_mines > 0:
            number_color = self.COLORS.get(
                f'NUMBER_{cell.adjacent_mines}', 
                self.COLORS['TEXT']
            )
            text = self.font_small.render(
                str(cell.adjacent_mines), 
                True, 
                number_color
            )
            text_rect = text.get_rect(center=rect.center)
            self.screen.blit(text, text_rect)
    else:
        pygame.draw.rect(self.screen, self.COLORS['CELL_HIDDEN'], rect)
        pygame.draw.rect(self.screen, self.COLORS['GRID'], rect, 1)
        
        # 如果有旗帜
        if cell.is_flagged:
            pygame.draw.line(
                self.screen, 
                self.COLORS['FLAG'], 
                (rect.centerx, rect.top + 5),
                (rect.centerx, rect.bottom - 5),
                2
            )
            pygame.draw.polygon(
                self.screen, 
                self.COLORS['FLAG'], 
                [
                    (rect.centerx, rect.top + 5),
                    (rect.right - 5, rect.top + 15),
                    (rect.centerx, rect.top + 25)
                ]
            )

def draw_header(self) -> None:
    """绘制游戏头部"""
    header_rect = pygame.Rect(0, 0, self.screen_width, self.header_height)
    pygame.draw.rect(self.screen, self.COLORS['HEADER'], header_rect)
    
    # 绘制剩余地雷数
    mines_left = max(0, self.mines - self.flags_placed)
    mines_text = self.font_large.render(f"地雷: {mines_left}", True, self.COLORS['TEXT'])
    self.screen.blit(mines_text, (20, 30))
    
    # 绘制计时器
    if not self.first_click and not self.game_over and not self.victory:
        self.elapsed_time = (pygame.time.get_ticks() - self.start_time) // 1000
        
    time_text = self.font_large.render(f"时间: {self.elapsed_time}s", True, self.COLORS['TEXT'])
    self.screen.blit(time_text, (self.screen_width - 20 - time_text.get_width(), 30))
    
    # 绘制重置按钮
    pygame.draw.rect(self.screen, self.COLORS['CELL_HIDDEN'], self.reset_button)
    pygame.draw.rect(self.screen, self.COLORS['GRID'], self.reset_button, 2)
    
    if self.victory:
        reset_text = self.font_small.render("胜利!", True, self.COLORS['TEXT'])
    elif self.game_over:
        reset_text = self.font_small.render("失败!", True, self.COLORS['TEXT'])
    else:
        reset_text = self.font_small.render("重置", True, self.COLORS['TEXT'])
        
    reset_text_rect = reset_text.get_rect(center=self.reset_button.center)
    self.screen.blit(reset_text, reset_text_rect)

def reset_game(self) -> None:
    """重置游戏"""
    self.board = [[Cell(x, y) for y in range(self.height)] for x in range(self.width)]
    self.game_over = False
    self.victory = False
    self.first_click = True
    self.revealed_cells = 0
    self.flags_placed = 0
    self.elapsed_time = 0

def run(self) -> None:
    """运行游戏主循环"""
    running = True
    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            elif event.type == pygame.MOUSEBUTTONDOWN:
                x, y = event.pos
                if self.reset_button.collidepoint(x, y):
                    self.reset_game()
                else:
                    self.handle_click(x, y, event.button)
        
        # 绘制游戏界面
        self.screen.fill(self.COLORS['BACKGROUND'])
        self.draw_header()
        
        for x in range(self.width):
            for y in range(self.height):
                self.draw_cell(self.board[x][y])
        
        # 如果游戏结束,显示所有地雷
        if self.game_over:
            for x in range(self.width):
                for y in range(self.height):
                    cell = self.board[x][y]
                    if cell.is_mine and not cell.is_flagged:
                        cell.is_revealed = True
                    elif cell.is_flagged and not cell.is_mine:
                        cell.is_revealed = True
        
        pygame.display.flip()
        self.clock.tick(60)
    
    pygame.quit()
    sys.exit()

if name == "main":
# 创建并运行游戏
game = Minesweeper(width=10, height=10, mines=10)
game.run() `

posted @ 2025-06-17 09:23  黎孜  阅读(12)  评论(0)    收藏  举报