You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
261 lines
12 KiB
261 lines
12 KiB
import sys
|
|
import time
|
|
import random
|
|
import pygame
|
|
from pygame.locals import *
|
|
#游戏基本设定
|
|
M = 15 #行数
|
|
N = 15 #列数
|
|
MINE_COUNT = 50 #雷数
|
|
|
|
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 = 'normal' #格子状态, normal表示未被挖开.
|
|
self.set_value(value)
|
|
|
|
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)
|
|
|
|
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)
|
|
|
|
def get_status(self): #格子状态(没挖, 挖了, 标记了等)
|
|
return self._status
|
|
def set_status(self, value):
|
|
self._status = value
|
|
status = property(fget=get_status, fset=set_status)
|
|
def _get_around(x, y):
|
|
return [(i, j) for i in range(max(0, x - 1), min(N - 1, x + 1) + 1)
|
|
for j in range(max(0, y - 1), min(M - 1, y + 1) + 1) if i != x or j != y]
|
|
#max()和min()应对边界的格子.
|
|
|
|
class MineBlock:
|
|
def __init__(self):
|
|
self._block = [[Mine(i, j) for i in range(N)] for j in range(M)]
|
|
#用前面的Mine()类生成的列表和网格同构
|
|
for i in random.sample(range(N * M), MINE_COUNT): # 进行一个雷的埋
|
|
self._block[i // N][i % N].value = 1 #注意雷被赋值为1
|
|
def get_block(self):
|
|
return self._block
|
|
block = property(fget=get_block)
|
|
|
|
def getmine(self, x, y): #返回是0还是1
|
|
return self._block[y][x]
|
|
def open_mine(self, x, y): #为了返回是否挖到雷, 挖到就饭后False, #悄悄催更某鸽子的爆炸电台, Bomb!
|
|
if self._block[y][x].value:
|
|
self._block[y][x].status = 'bomb' #标记为寄
|
|
return False #1就会执行到这里, 这里是灵魂的终点
|
|
self._block[y][x].status = 'opened' #否则咱先标记为open
|
|
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
|
|
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 double_mouse_button_down(self, x, y): #左右鼠标同时按下
|
|
if self._block[y][x].around_mine_count == 0: #是0就周围一圈都处理下
|
|
return True
|
|
self._block[y][x].status = 'double' #状态设为双击ing
|
|
around = _get_around(x, y)
|
|
# 准备计算周围被标记的雷数量
|
|
sumflag = 0
|
|
for i, j in _get_around(x, y):
|
|
if self._block[j][i].status == '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 == 'normal':
|
|
if not self.open_mine(i, j):
|
|
result = False
|
|
else: #没标记完毕就闪烁一下
|
|
for i, j in around:
|
|
if self._block[j][i].status == 'normal': #完成闪烁
|
|
self._block[j][i].status = 'hint'
|
|
return result
|
|
def double_mouse_button_up(self, x, y):
|
|
self._block[y][x].status = 'opened'
|
|
for i, j in _get_around(x, y):
|
|
if self._block[j][i].status == 'hint':
|
|
self._block[j][i].status = 'normal'
|
|
|
|
SIZE = 30 #每个方块的像素大小
|
|
SCREEN_WIDTH = N * SIZE
|
|
SCREEN_HEIGHT = (M + 2) * SIZE
|
|
|
|
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('F:/Work/Python_Work/minesweeper-main/resources/a.TTF', SIZE * 2)
|
|
fwidth, fheight = font1.size('999')
|
|
red = (200, 40, 40)
|
|
#你也不想你的图片有大有小吧
|
|
img0 = pygame.image.load('F:/Work/Python_Work/minesweeper-main/resources/0.bmp').convert()
|
|
img0 = pygame.transform.smoothscale(img0, (SIZE, SIZE))
|
|
img1 = pygame.image.load('F:/Work/Python_Work/minesweeper-main/resources/1.bmp').convert()
|
|
img1 = pygame.transform.smoothscale(img1, (SIZE, SIZE))
|
|
img2 = pygame.image.load('F:/Work/Python_Work/minesweeper-main/resources/2.bmp').convert()
|
|
img2 = pygame.transform.smoothscale(img2, (SIZE, SIZE))
|
|
img3 = pygame.image.load('F:/Work/Python_Work/minesweeper-main/resources/3.bmp').convert()
|
|
img3 = pygame.transform.smoothscale(img3, (SIZE, SIZE))
|
|
img4 = pygame.image.load('F:/Work/Python_Work/minesweeper-main/resources/4.bmp').convert()
|
|
img4 = pygame.transform.smoothscale(img4, (SIZE, SIZE))
|
|
img5 = pygame.image.load('F:/Work/Python_Work/minesweeper-main/resources/5.bmp').convert()
|
|
img5 = pygame.transform.smoothscale(img5, (SIZE, SIZE))
|
|
img6 = pygame.image.load('F:/Work/Python_Work/minesweeper-main/resources/6.bmp').convert()
|
|
img6 = pygame.transform.smoothscale(img6, (SIZE, SIZE))
|
|
img7 = pygame.image.load('F:/Work/Python_Work/minesweeper-main/resources/7.bmp').convert()
|
|
img7 = pygame.transform.smoothscale(img7, (SIZE, SIZE))
|
|
img8 = pygame.image.load('F:/Work/Python_Work/minesweeper-main/resources/8.bmp').convert()
|
|
img8 = pygame.transform.smoothscale(img8, (SIZE, SIZE))
|
|
img_blank = pygame.image.load('F:/Work/Python_Work/minesweeper-main/resources/blank.bmp').convert()
|
|
img_blank = pygame.transform.smoothscale(img_blank, (SIZE, SIZE))
|
|
img_flag = pygame.image.load('F:/Work/Python_Work/minesweeper-main/resources/flag.bmp').convert()
|
|
img_flag = pygame.transform.smoothscale(img_flag, (SIZE, SIZE))
|
|
img_ask = pygame.image.load('F:/Work/Python_Work/minesweeper-main/resources/ask.bmp').convert()
|
|
img_ask = pygame.transform.smoothscale(img_ask, (SIZE, SIZE))
|
|
img_mine = pygame.image.load('F:/Work/Python_Work/minesweeper-main/resources/mine.bmp').convert()
|
|
img_mine = pygame.transform.smoothscale(img_mine, (SIZE, SIZE))
|
|
img_blood = pygame.image.load('F:/Work/Python_Work/minesweeper-main/resources/blood.bmp').convert()
|
|
img_blood = pygame.transform.smoothscale(img_blood, (SIZE, SIZE))
|
|
img_error = pygame.image.load('F:/Work/Python_Work/minesweeper-main/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('F:/Work/Python_Work/minesweeper-main/resources/face_fail.bmp').convert()
|
|
img_face_fail = pygame.transform.smoothscale(img_face_fail, (face_size, face_size))
|
|
img_face_normal = pygame.image.load('F:/Work/Python_Work/minesweeper-main/resources/face_normal.bmp').convert()
|
|
img_face_normal = pygame.transform.smoothscale(img_face_normal, (face_size, face_size))
|
|
img_face_success = pygame.image.load('F:/Work/Python_Work/minesweeper-main/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 = '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 == 'started':
|
|
if b1 and b3:
|
|
mine = block.getmine(x, y)
|
|
if mine.status == 'opened':
|
|
if not block.double_mouse_button_down(x, y):
|
|
game_status = '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:
|
|
block = MineBlock()
|
|
start_time = time.time()
|
|
game_status = 'readied'
|
|
elapsed_time = 0
|
|
continue
|
|
if game_status == 'readied':
|
|
game_status = 'started'
|
|
start_time = time.time()
|
|
elapsed_time = 0
|
|
if game_status == 'started':
|
|
mine = block.getmine(x, y)
|
|
if b1 and not b3:
|
|
if mine.status == 'normal':
|
|
if not block.open_mine(x, y):
|
|
game_status = 'over'
|
|
elif not b1 and b3:
|
|
if mine.status == 'normal':
|
|
mine.status = 'flag'
|
|
elif mine.status == 'flag':
|
|
mine.status = 'ask'
|
|
elif mine.status == 'ask':
|
|
mine.status = 'normal'
|
|
elif b1 and b3:
|
|
if mine.status == '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 == 'opened':
|
|
screen.blit(img_dict[mine.around_mine_count], pos)
|
|
opened_count += 1
|
|
elif mine.status == 'double':
|
|
screen.blit(img_dict[mine.around_mine_count], pos)
|
|
elif mine.status == 'bomb':
|
|
screen.blit(img_blood, pos)
|
|
elif mine.status == 'flag':
|
|
screen.blit(img_flag, pos)
|
|
flag_count += 1
|
|
elif mine.status == 'ask':
|
|
screen.blit(img_ask, pos)
|
|
elif mine.status == 'hint':
|
|
screen.blit(img0, pos)
|
|
elif game_status == 'over' and mine.value:
|
|
screen.blit(img_mine, pos)
|
|
elif mine.value == 0 and mine.status == 'flag':
|
|
screen.blit(img_error, pos)
|
|
elif mine.status == '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 == '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 == M*N:
|
|
game_status = 'win'
|
|
#给你脸了
|
|
if game_status == 'over':
|
|
screen.blit(img_face_fail, (face_pos_x, face_pos_y))
|
|
elif game_status == '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() |