# -*- coding: utf-8 -*-

# __/author__by:Kevin_F/__

import tkinter.messagebox

import random

import time

import pygame

import tkinter

import tkinter.messagebox

num_w = 30 # 横向格子数

num_h = 16 # 竖向格子数

# 界面初始化

def window_init():

pygame.init()

global window

# 格子尺寸30*30,状态栏高度100,上下左右边界20

window = pygame.display.set_mode((30 * num_w + 20 * 2, 100 + 30 * num_h + 2 * 40))

pygame.display.set_caption('扫雷xp')

window.fill((128, 138, 135)) # 背景色:冷灰

pygame.draw.rect(window, (192, 192, 192), (0, 0, 30 * num_w + 20 * 2, 100)) # 最上面状态框

for j in range(num_h):

for i in range(num_w):

# 格子坐标

block_x = 20 + i * 30

block_y = 100 + 20 + j * 30

list_block.append([block_x, block_y, 0, 0])

list_block_pos.append((block_x, block_y))

"""

list_temp生成存放每一行中格子的坐标信息

block_x:格子的x坐标

block_y:格子的y坐标 (坐标信息是固定不可修改的,所以用元组表示)

0:定义此格子是否是雷 是雷:-1 不是雷:表示周边相邻非雷格子的数量,先写入默认值为0

0:定义格子的标记状态 0-未标记,即初始值 1-标记是雷 2-标记问号 3-左击点开

"""

pygame.draw.rect(window, (192, 192, 192), (block_x, block_y, 30, 30), 0) # 实心格子

pygame.draw.rect(window, (220, 220, 220), (block_x, block_y, 30, 30), 2) # 格子边线

pygame.display.flip()

# 状态栏 雷剩余数

def bomb_les():

global count_bomb

if count_bomb < 0:

count_bomb = 0

# 不存在标记雷超过99的可能,因为未标记的状态只有先标记成雷-1,再右键取消标记雷+1

pygame.draw.rect(window, (192, 192, 192), (0, 0, 150, 100), 0)

font_bomb_num = pygame.font.SysFont('Microsoft YaHei', 60, bold=True)

bomb_num = font_bomb_num.render(str(count_bomb), True, (255, 0, 0))

window.blit(bomb_num, (20, 10))

pygame.display.update()

# 状态栏 状态显示

def game_status(status):

img_working = pygame.image.load('me.png')

img_bad = pygame.image.load('yc.png')

img_win = pygame.image.load('yes.png')

if status == 'working': # 游戏开始时的图片

window.blit(img_working, (15 * num_w + 20 - 45, 5))

elif status == 'loose': # 游戏失败的图片

window.blit(img_bad, (15 * num_w + 20 - 45, 5))

elif status == 'win': # 游戏胜利的图片

window.blit(img_win, (15 * num_w + 20 - 45, 5))

else:

pass

pygame.display.update()

# 游戏初始化(随机生成a颗雷,初始化每个格子的位置信息,状态信息)

def game_init():

# 随机生成99颗地雷

a = random.randint(10, 100)

global list_bomb_pos

list_bomb_pos = random.sample(list_block_pos, a)

# 从所有格子中取不重复的99个,即得到99个位置坐标(x,y),组成的列表即是所有雷的坐标列表

# 改写list_block中格子的第三个值 从0改成-1 即表示是雷

for i in range(len(list_bomb_pos)):

for j in range(len(list_block)):

if list_block[j][0] == list_bomb_pos[i][0] and list_block[j][1] == list_bomb_pos[i][1]:

list_block[j][2] = -1

# 不是雷的格子,要计算出格子周边的雷数,并写入list_block

for index in range(len(list_block)):

# index为list_block的下标

x = index % 30

y = index // 30

if list_block[index][2] == -1:

continue

else:

list_beside = list_side(x, y)

mark_num = 0 # 定义一个变量,用于存放此格子周边是雷的格子的个数

for element in list_beside:

if element[2] == -1:

mark_num += 1

list_block[index][2] = mark_num # 将周边雷的个数写入list_block中的第三个值

# 初始化一个列表,用于存放不是雷的格子的坐标

for i in list_block_pos:

if i not in list_bomb_pos:

list_not_bomb.append(i)

# 获得一个存放此格子周边相邻格子组成的列表(定义此函数返回值就是这个列表)

def list_side(x, y):

if 1 <= x <= 28 and 1 <= y <= 14:

list_side = [

list_block[x - 1 + (y - 1) * 30],

list_block[x + (y - 1) * 30],

list_block[x + 1 + (y - 1) * 30],

list_block[x - 1 + y * 30],

list_block[x + 1 + y * 30],

list_block[x - 1 + (y + 1) * 30],

list_block[x + (y + 1) * 30],

list_block[x + 1 + (y + 1) * 30]

]

elif x == 0 and 1 <= y <= 14:

list_side = [

list_block[(y - 1) * 30],

list_block[1 + (y - 1) * 30],

list_block[1 + y * 30],

list_block[(y + 1) * 30],

list_block[1 + (y + 1) * 30]

]

elif x == 29 and 1 <= y <= 14:

list_side = [

list_block[28 + (y - 1) * 30],

list_block[29 + (y - 1) * 30],

list_block[28 + y * 30],

list_block[28 + (y + 1) * 30],

list_block[29 + (y + 1) * 30]

]

elif 1 <= x <= 28 and y == 0:

list_side = [

list_block[x - 1 + y * 30],

list_block[x + 1 + y * 30],

list_block[x - 1 + (y + 1) * 30],

list_block[x + (y + 1) * 30],

list_block[x + 1 + (y + 1) * 30]

]

elif 1 <= x <= 28 and y == 15:

list_side = [

list_block[x - 1 + (y - 1) * 30],

list_block[x + (y - 1) * 30],

list_block[x + 1 + (y - 1) * 30],

list_block[x - 1 + y * 30],

list_block[x + 1 + y * 30]

]

elif x == 0 and y == 0:

list_side = [list_block[1], list_block[30], list_block[31]]

elif x == 0 and y == 15:

list_side = [list_block[420], list_block[421], list_block[451]]

elif x == 29 and y == 0:

list_side = [list_block[28], list_block[58], list_block[59]]

else:

list_side = [list_block[448], list_block[449], list_block[478]]

return list_side

# 绘制鼠标点击后的格子

def draw_block(para, x, y):

if para == 0: # 此格子周围格子都不是雷,此格子直接画个实心方块

pygame.draw.rect(window, (180, 180, 180), (x * 30 + 20, y * 30 + 120, 30, 30), 0)

elif para in [1, 2, 3, 4, 5, 6, 7, 8]: # 此格子周围有雷,显示周围雷的数量

colors = {

1: (0, 0, 255),

2: (34, 139, 34),

3: (25, 25, 112),

4: (160, 32, 240),

5: (94, 38, 18),

6: (199, 97, 20),

7: (240, 230, 140),

8: (240, 230, 140)

}

num_font = pygame.font.SysFont('SimHei', 24, bold=True)

text_num = num_font.render(str(para), True, colors[para])

w1, h1 = text_num.get_size()

window.blit(text_num, (x * 30 + 35 - w1 / 2, y * 30 + 135 - h1 / 2))

elif para == 'bomb': # 左键点击到雷的时候,地雷爆炸(变红色)

pygame.draw.circle(window, (0, 0, 0), (x * 30 + 35, y * 30 + 135), 12)

elif para == 'mark': # 右键标记为雷时,画个红色实心圆表示地雷

pygame.draw.rect(window, (192, 192, 192), (x * 30 + 20, y * 30 + 120, 30, 30), 0) # 实心格子

pygame.draw.rect(window, (220, 220, 220), (x * 30 + 20, y * 30 + 120, 30, 30), 2) # 格子边线

pygame.draw.circle(window, (255, 0, 0), (x * 30 + 35, y * 30 + 135), 11)

elif para == '?': # 右键标记?,格子上显示?

num_font = pygame.font.SysFont('SimHei', 24)

text_num = num_font.render('?', True, (255, 0, 0))

w1, h1 = text_num.get_size()

pygame.draw.rect(window, (192, 192, 192), (x * 30 + 20, y * 30 + 120, 30, 30), 0) # 实心格子

pygame.draw.rect(window, (220, 220, 220), (x * 30 + 20, y * 30 + 120, 30, 30), 2) # 格子边线

window.blit(text_num, (x * 30 + 35 - w1 / 2, y * 30 + 135 - h1 / 2))

elif para == 'blank': # 右键切换成未标记状态时,画为初始化时的格子

pygame.draw.rect(window, (192, 192, 192), (x * 30 + 20, y * 30 + 120, 30, 30), 0) # 实心格子

pygame.draw.rect(window, (220, 220, 220), (x * 30 + 20, y * 30 + 120, 30, 30), 2) # 格子边线

else:

pass

pygame.display.update()

# 扫雷区鼠标左击事件

def mouse_click_left(mouse_x, mouse_y):

global list_block, is_loose, count_click

pos_x = (mouse_x - 20) // 30

pos_y = (mouse_y - 120) // 30

index = pos_x + pos_y * 30 # list_block的下标index

# 触发了此位置的左击事件,要先把此位置的左击事件表达出来

if list_block[index][3] == 3: # 如果这个格子已经被左击点开过,则不能重复点击

pass

else:

# 先判断点击是否是雷 ,如果是雷,游戏失败

if list_block[index][2] == -1: # 鼠标左击 是雷 游戏失败

is_loose = True

for x, y in list_bomb_pos:

draw_block('bomb', (x - 20) // 30, (y - 120) // 30)

# 把当前点击的这个雷标成红色

pygame.draw.rect(window, (255, 0, 0), (20 + pos_x * 30, 120 + pos_y * 30, 30, 30), 0)

draw_block('bomb', pos_x, pos_y)

game_status('loose')

# 游戏已经失败,这个时候再点击扫雷区,无效

# 计时停止

else:

# 不是雷的情况下,再判断这个格子是否是周边雷数为0 ,如果为0 ,则要继续触发左击点开该格子周围8个格子

# 除了画出当前位置的左击事件,还需要判断当前周边雷数是否为0

# 如果为0,自动触发此格子周边8个相邻格子的左击事件(因为0 代表周边8个格子都不是雷,直接自动左击显示出这8个格子每一个的周边雷数)

# 如果这8个格子中还有周边雷数为0的,则递归调用函数

if list_block[index][2] == 0:

draw_block(list_block[index][2], pos_x, pos_y)

list_block[index][3] = 3

list_beside = list_side(pos_x, pos_y)

for i in list_beside:

x = (i[0] - 20) // 30

y = (i[1] - 120) // 30

if list_block[x + 30 * y][3] == 0: # 判断此位置的标记状态(list_block里的最后一个参数),0-未标记

mouse_click_left(x * 30 + 20, y * 30 + 120) # 调用函数

draw_block(list_block[x + 30 * y][2], x, y) # 画出左击后的图形

list_block[x + 30 * y][3] = 3 # 调用函数,即说明发生左击(即使是电脑自动触发,而非人为操作),更改标记状态为3

else: # 该格子周边雷数不为0,直接显示该格子的周边雷数

draw_block(list_block[index][2], pos_x, pos_y)

list_block[index][3] = 3

count_click = 0

for i in list_block:

if i[3] == 3:

count_click += 1

# 每次触发鼠标左击事件后,都重新统计已经左击点开的格子个数

# 为了后面判断如果点开的格子个数=非雷的格子总数,则游戏胜利

# 扫雷区鼠标右击事件

def mouse_click_right(mouse_x, mouse_y):

global count_bomb

pos_x = (mouse_x - 20) // 30

pos_y = (mouse_y - 120) // 30

index = pos_x + pos_y * 30 # list_block的下标index

status = list_block[index][3]

# 游戏结束,不能再右击

if is_loose:

import tkinter.messagebox

tkinter.messagebox.showinfo('扫雷xp','你死了')

# -*- conding:utf-8 -*-

while True:

# 检查音乐流播放,有返回True,没有返回False

# 如果没有音乐流则选择播放

if pygame.mixer.music.get_busy() == False:

pygame.mixer.music.play()

else:

# 右击,格子显示状态在0-未标记 1-标记雷 2-标记? 三种状态之间循环切换

if status == 0: # 如果此格子当前处于未标记状态

draw_block('mark', pos_x, pos_y)

list_block[index][3] = 1

count_bomb -= 1

elif status == 1:

draw_block('?', pos_x, pos_y)

list_block[index][3] = 2

count_bomb += 1

elif status == 2:

draw_block('blank', pos_x, pos_y)

list_block[index][3] = 0

else:

# 已经左击点开的位置 不能在右击(即status=3的情况)

pass

# 扫雷区鼠标中键事件

def mouse_click_mid(mouse_x, mouse_y):

# 鼠标中键该格子,表示扫描该格子周边相邻格子

# 该格子只有被左击点开(list_block[index][3]==3),且该格子周边雷数(list_block[index][2])=标记雷的总个数

# 中键触发自动左键点开周边非雷的格子(之前没有左击点开过 ),如果之前左击点开过,则跳过

pos_x = (mouse_x - 20) // 30

pos_y = (mouse_y - 120) // 30

index = pos_x + pos_y * 30 # list_block的下标index

status = list_block[index][3]

list_beside = list_side(pos_x, pos_y)

mark_bomb_sum = 0

for item in list_beside:

if item[3] == 1: # item[3]即相当于list_block[index][3] 如果该值为1 表示标记是雷

mark_bomb_sum += 1

if list_block[index][3] == 3 and list_block[index][2] == mark_bomb_sum and list_block[index][2] != 0:

# 该格子只有被左击点开(list_block[index][3]==3),且该格子周边雷数(list_block[index][2])=标记雷的总个数,且不等于0

for item in list_beside:

# 中键触发自动左键点开周边非雷的格子(之前没有左击点开过 ),如果之前左击点开过,则跳过

if item[3] == 3 or item[3] == 1 or item[3] == 2:

# 状态是3,表示左击点开过,状态为1 ,表示标记是雷,状态为2,表示疑问,这三种情况都不能触发鼠标左击事件

continue

else:

mouse_click_left(item[0], item[1])

def main():

global is_loose, list_block, list_block_pos, list_bomb_pos, list_not_bomb, count_click, count_bomb, num_not_bomb, t_start

list_block_pos = [] # 用于存放每个格子的位置坐标信息(x,y)

list_block = [] # 用于存放每个格子的坐标和状态信息,即每个元素=[x,y,0,0]

list_bomb_pos = [] # 用于存放雷的元素的坐标

list_not_bomb = [] # 用于存放不是雷的格子的坐标

count_click = 0 # 用于记录左击点开的格子数量

window_init()

game_status('working')

game_init()

is_loose = False

num_not_bomb = len(list_block_pos) - len(list_bomb_pos)

count_bomb = len(list_bomb_pos)

while True:

bomb_les()

if 0 <= count_click < num_not_bomb and not is_loose:

if count_click == 0:

t_start = int(time.time())

# 在while True循环内,如果count_click=0,表示没有鼠标左击,此时不计时

# 此时,因为while True一直循环,所以会一直刷新t_start的值,不断获取当前时间

# 当count_click从1开始,即一旦发生左击点击,上面if条件 count_click==0不成立,则不会再刷新t_start的值

# t_start的值固定在count_click=1前上一次循环的值,即左击点击之前的最后的一次循环的值,从而实现左击开始计时

t_show = int(time.time()) - t_start

pygame.draw.rect(window, (192, 192, 192), (720, 0, 200, 100), 0)

font_time = pygame.font.SysFont('Microsoft YaHei', 60, bold=True)

text_time = font_time.render(str(t_show), True, (255, 0, 0))

window.blit(text_time, (920 - text_time.get_size()[0], 10)) # 时间靠右显示

pygame.display.update()

else: # 如果游戏成功(count_click = num_not_bomb) 或者游戏失败(is_loose=True) 都停止时间显示

# !/usr/bin/python

# -*- coding: UTF-8 -*-

# Python2.x 导入方法

# Python3.x 导入方法

# from tkinter import *

pass

for event in pygame.event.get():

if event.type == pygame.QUIT:

exit()

elif event.type == pygame.MOUSEBUTTONDOWN:

if is_loose:

game_status('loose')

continue

elif count_click < num_not_bomb:

mouse_x, mouse_y = pygame.mouse.get_pos()

click = pygame.mouse.get_pressed()

if 20 <= mouse_x <= 920 and 120 <= mouse_y <= 600:

if click == (True, False, False): # 鼠标左击

mouse_click_left(mouse_x, mouse_y)

elif click == (False, True, False): # 鼠标中键

mouse_click_mid(mouse_x, mouse_y)

elif click == (False, False, True): # 鼠标右键

mouse_click_right(mouse_x, mouse_y)

else: # 当count_click == num_not_bomb,则说明所有非雷的格子全部被点开,游戏胜利

game_status('win')

elif event.type == pygame.MOUSEBUTTONUP:

mouse_x1, mouse_y1 = pygame.mouse.get_pos()

if 0 <= mouse_x1 - (15 * num_w + 20 - 45) <= 90 and 10 <= mouse_y1 <= 100:

# 鼠标在状态图标位置左击点击时,表示游戏开始

return main() # 游戏开始或者游戏重新开始

if __name__ == '__main__':

import tkinter

import PySimpleGUI as sg

count = range(100)

for i, item in enumerate(count):

sg.one_line_progress_meter('扫雷xp', i + 1, len(count), '扫雷xp进度')

# 假设这代码部分需要0.05s

time.sleep(0.000001)

main()

有图和pygame就行

图片:

 

 

 

运行截图:

相关文章

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: