image image image image image image image

1 条评论

  • @ 2024-6-15 19:57:43
    import sys
    import time,random
    import pygame
    from pygame.locals import *
    from enum import Enum
    
    '''
    增加计时和暂停
    '''
    
    BLOCK_WIDTH = 30   # 棋盘的宽度方块个数
    BLOCK_HEIGHT = 15  # 棋盘的高度方块个数
    SIZE = 30    # 方块的长宽
    MINE_COUNT = 70   # 雷的数量
    
    # 游戏屏幕的宽
    SCREEN_WIDTH = BLOCK_WIDTH * SIZE
    # 游戏屏幕的高
    SCREEN_HEIGHT = (BLOCK_HEIGHT + 2) * SIZE
    
    def load_img(file,size):
        img = pygame.image.load(file).convert()
        return pygame.transform.smoothscale(img,(size,size))
    
    # 定义方块类
    class Mine:
        def __init__(self, row, column, value=0):
            self.row = row
            self.column = column
            self.pos = (self.column * SIZE, (self.row + 2) * SIZE)
            self.value = value   # 1:雷 0:安全
            self.status = BlockStatus.normal
            self.around_mine_count = -1  # 周围雷的数量
            self.image = load_img('resources/normal.jpg',SIZE)
    
        def __repr__(self):
            return str(self.value)
    
    # 定义雷区
    class MineBlock:
        def __init__(self):
            # 生成方块棋盘组成列表,无地雷,每个方块是一个Mine实例()
            # 在 ipython 等终端中展示一下结果,有一个直观印象。
            # 列表推导式的用法
            self.blocks = [Mine(i, j) for i in range(BLOCK_HEIGHT) for j in range(BLOCK_WIDTH)]
    
            # 埋雷
            # 在总方块里随机选MINE_COUNT个数,做雷。
            mines = random.sample(range(BLOCK_WIDTH * BLOCK_HEIGHT), MINE_COUNT)
            for i in mines:
                self.blocks[i].value = 1
    
        # 返回指定行列的 mine 对象
        def getmine(self, row, column):
            return self.blocks[row * BLOCK_WIDTH + column]
    
        def get_around(self,row,column):
            return [(i,j) for i in range(max(row - 1, 0), min(row + 2, BLOCK_HEIGHT))
                    for j in range(max(column-1,0),min(column+2,BLOCK_WIDTH))
                    if not(i == row and j == column)]
    
    
        def open_mine(self, r, c):
            mine = self.getmine(r,c) #返回指定行列的 mine 对象
            if mine.status == BlockStatus.normal: # 判断方块的状态是否为未点击
                if mine.value: # mine.value # 1:雷 0:安全
                    mine.status = BlockStatus.bomb # 是雷把这个方块状态更改为# 踩中地雷
                    for m in self.blocks: # 遍历所有方块
                        if m.value == 1: # 找到所有是雷的方块
                            m.image = load_img("resources/mine.bmp", SIZE) # 把方块的图片更新为普通地雷
                    mine.image = load_img("resources/bomb.bmp", SIZE) #把踩到的方块的图片更新为红色地雷
                    return False # 结束游戏
    
                mine.status = BlockStatus.opened # 如果不是地雷,就把方块状态更改为打开
                around = self.get_around(r, c) # 调用get_around()找到这个方块的所有朋友
                sum = 0 # 定义一个累加器变量记录朋友中有多少个地雷
                for i, j in around: # 遍历所有朋友,是地雷就sum加一
                    if self.getmine(i, j).value == 1:
                        sum += 1
                mine.around_mine_count = sum # around_mine_count 更新mine方块周围雷的数量
    
                if sum == 0: # 判断mine方块周围雷的数量是否为0
                    mine.image = load_img("resources/blank.bmp", SIZE) # 把mine方块图片设置为空
                    for i ,j in around: # 遍历所有朋友
                        if self.getmine(i,j).around_mine_count == -1: #如果朋友周围雷数量为-1就打开它
                            self.open_mine(i,j)
                elif mine.around_mine_count == -1:
                    pass
                else:
                    mine.image = load_img(f"resources/{mine.around_mine_count}.bmp", SIZE)
            return True
    
    def print_text(screen, font, x, y, text, fcolor=(255, 255, 255)):
        imgText = font.render(text, True, fcolor)
        screen.blit(imgText, (x, y))
    
    class BlockStatus(Enum):
        normal = 1  # 未点击
        opened = 2  # 已点击
        mine = 3    # 地雷
        flag = 4    # 标记为地雷
        ask = 5   # 标记为问号
        bomb = 6    # 踩中地雷
    
    class GameStatus(Enum):
        ready = 1
        start = 2
        over = 3
        win = 4
    
    def main():
        pygame.init()
        screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
        pygame.display.set_caption('扫雷')
        bgcolor = (225, 225, 225)   # 背景色
    
        font1 = pygame.font.Font('resources/msyh.ttf', SIZE * 2)  # 得分的字体
        fwidth, fheight = font1.size('999')    # 具体的文本 999 的宽和高
        red = (200, 40, 40)
    
        block = MineBlock()
        game_status = GameStatus.ready
        flag_count = 0
        start_time = pause_time = spend_time = 0
    
        # 导入face图片
        face_size = int(SIZE * 1.25)
        img_face_normal = load_img("resources/face_normal.bmp",face_size)
        img_face_fail = load_img("resources/face_fail.bmp",face_size)
        img_face_win = load_img("resources/face_win.bmp",face_size)
        face_pos_x = (SCREEN_WIDTH - face_size) // 2
        face_pos_y = (SIZE * 2 - face_size) // 2
    
        while True:
            # 填充背景色
            screen.fill(bgcolor)
    
            open_count = 0
            for mine in block.blocks:
                screen.blit(mine.image, mine.pos)
                if mine.value == 0 and mine.around_mine_count != -1:
                    open_count += 1
            if open_count == BLOCK_WIDTH * BLOCK_HEIGHT - MINE_COUNT:
                game_status = GameStatus.win
    
            screen.blit(img_face_normal,(face_pos_x,face_pos_y))
            if game_status == GameStatus.win:
                screen.blit(img_face_win,(face_pos_x,face_pos_y))
                print_text(screen,font1,face_pos_x+face_size+20,(SIZE * 2 - fheight)//2,"win!",red)
            elif game_status == GameStatus.over:
                screen.blit(img_face_fail,(face_pos_x,face_pos_y))
                print_text(screen,font1,face_pos_x+face_size+20,(SIZE * 2 - fheight)//2,"lose!",red)
    
    
            # 显示剩余旗子和所用时间
            if game_status == GameStatus.start:
                spend_time = int(time.time() - start_time - pause_time)
                print_text(screen,font1,30,(SIZE * 2 - fheight)//2, f"{spend_time}",red)      # 用时
            elif game_status == GameStatus.ready and spend_time == 0:
                print_text(screen,font1,30,(SIZE * 2 - fheight)//2, "0",red)
            else:
                print_text(screen,font1,30,(SIZE * 2 - fheight)//2, f"{spend_time}",red)
    
            flag_left = max(MINE_COUNT - flag_count, 0)
            print_text(screen,font1,SCREEN_WIDTH-fwidth,(SIZE * 2 - fheight)//2,f"{flag_left}",red)   # 剩余雷
    
            for event in pygame.event.get():
                if event.type == QUIT:
                    pygame.quit()
                    sys.exit()
                elif event.type == MOUSEBUTTONDOWN:
                    mouse_x, mouse_y = event.pos
                    column = mouse_x // SIZE
                    row = mouse_y // SIZE - 2    # 有上面的非雷区
                    b1, b2, b3 = pygame.mouse.get_pressed()
                elif event.type == MOUSEBUTTONUP:
                    # 雷区
                    if row >= 0:
                        mine = block.getmine(row, column)
    
                        if game_status == GameStatus.ready:
                            game_status = GameStatus.start
                            start_time = time.time()
                        if game_status == GameStatus.start:
                            # 点击左键
                            if b1 and not b3:
                                if not block.open_mine(row,column):
                                    game_status = GameStatus.over
    
                            # 点击右键
                            elif not b1 and b3:
                                if mine.status == BlockStatus.normal:
                                    mine.status = BlockStatus.flag
                                    mine.image = load_img("resources/flag.bmp", SIZE)
                                    flag_count += 1
                                elif mine.status == BlockStatus.flag:
                                    mine.status = BlockStatus.ask
                                    mine.image = load_img("resources/ask.bmp", SIZE)
                                    flag_count -= 1
                                elif mine.status == BlockStatus.ask:
                                    mine.status = BlockStatus.normal
                                    mine.image = load_img("resources/normal.jpg", SIZE)
                    # 点击笑脸
                    elif face_pos_x < mouse_x < face_pos_x + face_size and \
                        face_pos_y < mouse_y < face_pos_y + face_size:
                        # 暂停
                        if game_status == GameStatus.start:
                            game_status = GameStatus.ready
                            pause_start = time.time()
                        elif game_status == GameStatus.ready and spend_time != 0:
                            game_status = GameStatus.start
                            pause_end = time.time()
                            pause_time += int(pause_end - pause_start)
                        # 重新开始
                        elif game_status == GameStatus.win or game_status == GameStatus.over:
                            game_status = GameStatus.ready
                            block = MineBlock()
                            flag_count = 0
                            start_time = pause_time = spend_time = 0
    
            pygame.display.update()
    
    if __name__ == '__main__':
        main()
    
    
    
    • 1