查看原文
其他

迎中秋,我用Python开发了一款月饼拼图游戏,快来看看你要几步完成挑战吧

道才 可以叫我才哥 2023-02-06

大家好,我是才哥。

马上中秋了,不得不说,已经感受到了浓浓的中秋气氛,大家吃月饼都快吃“”了,毕竟公司之间月饼送来送去的。。

那么,今天才哥带大家玩点不一样的,咱们用Python写个益智拼图游戏,咱自己拼个月饼出来,顺便比拼一下IQ,看看最少几步搞定(欢迎留言区 留言)!

先看效果:(点击播放

接下来,我们介绍一下开发过程。

目录:

  • 1. 图片资源准备

  • 2. 拼图逻辑梳理

  • 3. 功能开发


1. 图片资源准备

案例中我们采用的是3×3的拼图结构,需要准备一张月饼图,建议是正方形的尺寸(当然大家学会后可以任意尺寸其实),然后将图片裁剪成3×3=9张。

这里采用的是PIL库的操作方法,关于该库的更多操作技巧大家可以参考此前推文《Python基础模块:图像处理模块@PIL(批量分类处理图片及添加水印)》。

from PIL import Image

img = Image.open(r'月饼.png'
# 设置裁剪的 分割
n = 3
# 重置 尺寸
img = img.resize((520520))
w, h = img.size

for i in range(n):
    for j in range(n):
        # 设置裁剪的 区域(左上及右下坐标)
        box = (h/n * i, h/n * j, w/n * (i+1), w/n * (j+1))
        # 裁剪
        region = img.crop(box) 
        # 保存裁剪后的图片
        region.save(f'{i+3*j}.png')
裁剪后


2. 拼图逻辑梳理

这里我们将采取TK库进行游戏制作,基于此我们梳理拼图逻辑。

  • 先构建一个画布区域
  • 然后将画布区域分为9份(本案例中),从左到右从上到下依次编号为0-8
  • 初始情况下,随机在每个区域填充一份月饼区域图(第1步中裁剪的,除了第8张),其中有一个区域为空
  • 点击月饼区域图,如果和空区域相邻则互换,每次互换则步数加1
  • 当画布区域和月饼区域一一对应,则成功

接下来,我们实现以上功能。


3. 功能开发

先构建画布区域和月饼区域图列表

import random
from tkinter.messagebox import *
from tkinter import *

# 画布区域(这里就是图片尺寸)
w = w
h = h
# 月饼区域图的边长
img_w = w // 3
img_h = h // 3
# 游戏的行列数
ROWS = 3
COLS = 3
# 移动步数
steps = 0
# 保存所有月饼区域图的列表
board = [[012],
         [345],
         [678]]
root = Tk('月饼拼图')
root.title("月饼拼图@可以叫我才哥")
# 载入月饼区域图9张(编号0-8)
Pics = []
for i in range(9):
    filename = f"{i}.png"
    Pics.append(PhotoImage(file=filename))

再定义一个月饼区域图的类

这个类包含编号和填充图的方法,create_image是在指定位置创建一张图

class Square:
    def __init__(self, orderID):
        self.orderID = orderID

    def draw(self, canvas, board_pos):
        img = Pics[self.orderID]
        canvas.create_image(board_pos, image=img)

初始化

就是随机打乱编号

def initBoard():
    # 创建 0-8 的数字列表
    L = list(range(9))  
    # 打乱列表顺序
    random.shuffle(L)
    # 为每个月饼区域块分配编号(随机)
    for i in range(ROWS):
        for j in range(COLS):
            idx = i * ROWS+j
            orderID = L[idx]
            # 8号就是左下角,这里需要空出来
            if orderID == 8:
                board[i][j] = None
            else:
                board[i][j] = Square(orderID)

填充画布区域块

用月饼区域图填充对应位置

def drawBoard(canvas):
    canvas.create_polygon((00, w, 0, w, h, 0, h), width=1, outline='white')
    for i in range(ROWS):
        for j in range(COLS):
            if board[i][j] != None:
                board[i][j].draw(canvas, (img_w*(j+0.5), img_h*(i+0.5)))

操作逻辑

鼠标点击判断,根据点击的区域块与空白块相邻关系决定互换逻辑(上下左右)

def mouseClick(pos):
    global steps
    r = int(pos.y // img_h)
    c = int(pos.x // img_w)
    if r < 3 and c < 3:
        if board[r][c] is None:
            return
        else:
            current_square = board[r][c]
            if r-1 >= 0 and board[r-1][c] is None:
                board[r][c] = None
                board[r-1][c] = current_square
                steps += 1
            elif c+1 <= 2 and board[r][c+1is None:
                board[r][c] = None
                board[r][c+1] = current_square
                steps += 1
            elif r+1 <= 2 and board[r+1][c] is None:
                board[r][c] = None
                board[r+1][c] = current_square
                steps += 1
            elif c-1 >= 0 and board[r][c-1is None:
                board[r][c] = None
                board[r][c-1] = current_square
                steps += 1
            lb["text"] = f"累计使用步数:{steps}"
            cv.delete('all'
            drawBoard(cv)
    if win():
        showinfo(title="提示", message="挑战成功!")

成功判断

当区域块和月饼区域块一一对应,则拼图挑战成功

def win(): 
    for i in range(ROWS): 
        for j in range(COLS): 
            if board[i][j] != None  and  board[i][j].orderID !=i * ROWS + j: 
                return False 
    return True

开始游戏与重置

def playGame(): 
    global steps  
    steps = 0 
    initBoard()

def rePlay(): 
    print("重新开始"
    playGame() 
    # 清除canvas画布上的内容
    cv.delete('all')  
    # 累计步数清零
    lb["text"] = "累计使用步数:0"
    drawBoard(cv)

执行语句

显示当前累计步数预计重置游戏按钮

if __name__ == "__main__":
    cv = Canvas(root, bg = 'white', width = w, height = h) 
    b1=Button(root,bg = 'yellow', text="重新开始",font = 20, command=rePlay,width=20,height=2
    lb=Label(root, text=f"累计使用步数:{steps}" ,fg="red", width=30, height=2, font=12
    lb.pack() 
    cv.bind("<Button-1>", mouseClick) 
    cv.find 
    cv.pack() 
    b1.pack() 
    playGame() 
    drawBoard(cv) 
    root.mainloop()

基于以上几步,我们就完成了本次的拼图游戏。

大家后台回复955,可以在迎中秋文件夹领取 拼图游戏 exe可执行文件进行体验。

如果你喜欢的话,还希望点赞+在看在看达到20个,可添加作者微信领取 完整代码




推荐阅读


用python开发一个炸金花小游戏,注意别玩上瘾了~~

2021-08-24

阿里年薪70万的数据分析师必须知道的5个Pandas数据合并技巧

2021-09-12

这个引发热议的数据处理需求,原来还有这么巧妙的解法~

2021-09-07

又鸽了?英雄联盟手游公测跳票跟我DNF手游有毛线关系!!

2021-09-10






扫描二维码添加

才哥个人微信


可以叫我才哥





您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存