百度网盘下载链接: https://pan.baidu.com/s/1q9VPkOYvI12LjqfQVRCF1Q
密码: 7wfg
# coding: utf-8
# 作者: Charles
# 公众号: Charles的皮卡丘
# 拼图小游戏
import os
import sys
import random
import pygame
from pygame.locals import *
# 定义常量
Window_Width = 500
Window_Height = 500
Background_Color = (255, 255, 255)
Red = (255, 0, 0)
Green = (0, 255, 0)
Blue = (0, 0, 255)
BLACK = (0, 0, 0)
FPS = 40
Num_Random = 100
# 退出
def Stop():
pygame.quit()
sys.exit()
# 判断游戏是否结束
def isOver(board,size):
try:
Num_Cell = size * size
except:
Num_Cell = size[0] * size[1]
for i in range(Num_Cell-1):
if board[i] != i:
return False
return True
# 图片 空白 ===> 空白 图片
def moveR(board, blankCell, columns):
if blankCell % columns == 0: # 如果 空白在最左边则无法move
return blankCell
board[blankCell-1], board[blankCell] = board[blankCell], board[blankCell-1]
return blankCell-1
# 空白 图片 ===> 图片 空白
def moveL(board, blankCell, columns):
if (blankCell+1) % columns == 0: # 如果图片在最右边
return blankCell
board[blankCell+1], board[blankCell] = board[blankCell], board[blankCell+1]
return blankCell+1
'''
图片 空白
==>
空白 图片
'''
def MoveD(board, blankCell, columns):
if blankCell < columns: # 如果是第一行
return blankCell
board[blankCell-columns], board[blankCell] = board[blankCell], board[blankCell-columns]
return blankCell-columns
'''
空白 图片
==>
图片 空白
'''
def MoveU(board, blankCell, row, columns):
if blankCell >= (row-1) * columns: # 最后一行
return blankCell
board[blankCell+columns], board[blankCell] = board[blankCell], board[blankCell+columns]
return blankCell+columns
# 初始化打乱的图片 不断的随机打乱
def CreateBoard(row, columns, Num_Cell):
board = []
for i in range(Num_Cell):
board.append(i)
# 去掉右下角那块
blankCell = Num_Cell - 1
board[blankCell] = -1
for i in range(Num_Random):
# 0: left
# 1: right
# 2: up
# 3: down
direction = random.randint(0, 3)
if direction == 0:
blankCell = moveL(board, blankCell, columns)
elif direction == 1:
blankCell = moveR(board, blankCell, columns)
elif direction == 2:
blankCell = MoveU(board, blankCell, row, columns)
elif direction == 3:
blankCell = MoveD(board, blankCell, columns)
return board, blankCell
# 随机选取一张图片
def GetImagePath(filepath):
imgs = os.listdir(filepath)
if len(imgs) == 0:
print('[Error]: No pictures in filepath...')
return os.path.join(filepath, random.choice(imgs))
# 显示游戏结束界面
def Show_End_Interface(Demo, width, height):
Demo.fill(Background_Color)
font = pygame.font.Font('./font/simkai.ttf', width//8)
title = font.render('Finished!', True, (233, 150, 122))
rect = title.get_rect()
rect.midtop = (width/2, height/2.5)
Demo.blit(title, rect)
pygame.display.update()
pygame.time.wait(500)
while True:
for event in pygame.event.get():
if event.type == QUIT:
Stop()
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
Stop()
# 显示游戏开始界面
def Show_Start_Interface(Demo, width, height):
Demo.fill(Background_Color)
tfont = pygame.font.Font('./font/simkai.ttf', width//4)
cfont = pygame.font.Font('./font/simkai.ttf', width//20)
title = tfont.render('拼图游戏', True, Red)
content1 = cfont.render('按H或M或L键开始游戏,ESC键退出', True, Blue)
content2 = cfont.render('H为5*5模式,M为4*4模式,L为3*3模式', True, Blue)
trect = title.get_rect()
trect.midtop = (width/2, height/10)
crect1 = content1.get_rect()
crect1.midtop = (width/2, height/2.2)
crect2 = content2.get_rect()
crect2.midtop = (width/2, height/1.8)
Demo.blit(title, trect)
Demo.blit(content1, crect1)
Demo.blit(content2, crect2)
pygame.display.update()
while True:
size = None
for event in pygame.event.get():
if event.type == QUIT:
Stop()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
Stop()
if event.key == ord('l'):
size = 3
elif event.key == ord('m'):
size = 4
elif event.key == ord('h'):
size = 5
if size:
break
return size
# 主函数
def main(filepath):
# 初始化
pygame.init()
mainClock = pygame.time.Clock()
# 加载图片
gameImg = pygame.image.load(GetImagePath(filepath))
ImgRect = gameImg.get_rect()
# 设置窗口
Demo = pygame.display.set_mode((ImgRect.width, ImgRect.height))
pygame.display.set_caption('拼图游戏')
# 开始界面
size = Show_Start_Interface(Demo, ImgRect.width, ImgRect.height)
if isinstance(size, int):
row, columns = size, size
Num_Cell = size * size
elif len(size) == 2:
row, columns = size[0], size[1]
Num_Cell = size[0] * size[1]
else:
print('[Error]: Parameter Size error...')
Stop()
# 计算Cell大小
cellWidth = ImgRect.width // columns
cellHeight = ImgRect.height // row
# 游戏是否结束
over = False
# 避免初始化为原图
while True:
gameBoard, blankCell = CreateBoard(row, columns, Num_Cell)
if not isOver(gameBoard, size):
break
while True:
for event in pygame.event.get(): # 检查鼠标跟键盘的迹象
if event.type == QUIT:
Stop()
if over:
Show_End_Interface(Demo, ImgRect.width, ImgRect.height)
# 键盘操作
if event.type == KEYDOWN:
if event.key == K_LEFT or event.key == ord('a'):
blankCell = moveL(gameBoard, blankCell, columns)
elif event.key == K_RIGHT or event.key == ord('d'):
blankCell = moveR(gameBoard, blankCell, columns)
elif event.key == K_UP or event.key == ord('w'):
blankCell = MoveU(gameBoard, blankCell, row, columns)
elif event.key == K_DOWN or event.key == ord('s'):
blankCell = MoveD(gameBoard, blankCell, columns)
# 鼠标操作
if event.type == MOUSEBUTTONDOWN and event.button == 1:
x, y = pygame.mouse.get_pos()
x_pos = x // cellWidth
y_pos = y // cellHeight
idx = x_pos + y_pos * columns # 查看是第几行第几列 从而知道操作的是第几个
if idx == blankCell-1 or idx == blankCell+1 or idx == blankCell+columns or idx == blankCell-columns: # 如果idx 在空白页 上下左右任意一个方向
gameBoard[blankCell], gameBoard[idx] = gameBoard[idx], gameBoard[blankCell]
blankCell = idx
if isOver(gameBoard,size):
gameBoard[blankCell] = Num_Cell-1
over = True
Demo.fill(Background_Color) # 填充色为白色
for i in range(Num_Cell):
if gameBoard[i] == -1:
continue
x_pos = i // columns
y_pos = i % columns
rect = pygame.Rect(y_pos*cellWidth, x_pos*cellHeight, cellWidth, cellHeight) # 搞一个框框 标注 起始点 跟 长宽
ImgArea = pygame.Rect((gameBoard[i]%columns)*cellWidth, (gameBoard[i]//columns)*cellHeight, cellWidth, cellHeight)
Demo.blit(gameImg, rect, ImgArea) # #这里给了3个实参,分别是图像,绘制的位置,绘制的截面框
for i in range(columns+1): # 画线
pygame.draw.line(Demo, BLACK, (i*cellWidth, 0), (i*cellWidth, ImgRect.height))
for i in range(row+1): # 画线
pygame.draw.line(Demo, BLACK, (0, i*cellHeight), (ImgRect.width, i*cellHeight))
pygame.display.update() # 图片更新
mainClock.tick(FPS) # 频率
if __name__ == '__main__':
filepath = './pictures'
main(filepath)