借助第三方图片处理库pillow,处理图片。

1.将原图片分割为9个组成图片的文件,并命名。

import os
from PIL import Image


def splitimage(src, rownum, colnum, dstpath):  # 源文件、分为几行、分为几列,目标路径
    img = Image.open(src)
    w, h = img.size
    if rownum <= h and colnum <= w:
        print('原始图片信息:%sx%s, %s,%s ' % (w, h, img.format, img.mode))
        print('开始切割图片,请稍候..')
        s = os.path.split(src)
        if dstpath == '':  # 没输入路径
            dstpath = s[0]  # 使用原图片目录
        fn = s[1].split('.')  # s[1]为图片文件名
        basename = fn[0]  # 主文件名
        ext = fn[-1]  # 图片扩展名
        num = 0
        rowheight = h // rownum  # 每个块的高度
        colwidth = w // colnum  # 每块的宽度
        for r in range(rownum):
            for c in range(colnum):
                box = (c * colwidth, r * rowheight, (c + 1) * colwidth, (r + 1) * rowheight)
                img.crop(box).save(os.path.join(dstpath, basename + '_' + str(num) + '.' + ext))  # 分割并重命名
                num += 1
        print('图片处理完毕,共生成%s张图片' % num)
    else:
        print('不合法的切割参数')


src = input('请输入文件路径:')
if os.path.isfile(src):
    dstpath = input('请输入图片输出目录:(不输入路径则表示使用源路径)')
    if dstpath == '' or os.path.exists(dstpath):
        row = int(input('请输入切割行数:'))
        col = int(input('请输入切割列数:'))
        if row > 0 and col > 0:
            splitimage(src, row, col, dstpath)
        else:
            print('无效的行列切割数')
    else:
        print('图片输入目录%s不存在' % dstpath)
else:
    print('图片文件%s不存在!' % src)

 

2.游戏逻辑的实现,注意Pics.append(PhotoImage(file=filename)),只能处理gif格式文件

# -*- coding: utf-8 -*-
# @Time : 2020/12/14 13:49
# @Author : Zhenghui Lyu
# @File : luoji.py
# @Software: PyCharm

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

WIDTH = 312
HEIGHT = 450  # 画布大小

IMAGE_WIDTH = WIDTH // 3
IMAGE_HEIGHT = HEIGHT // 3  # 每个图片块大小

ROWS = 3
COLS = 3  # 三行三列

steps = 0

board = [[0, 1, 2], [3, 4, 5], [6, 7, 8]]

root = Tk('拼图游戏')

root.title('美女拼图')
Pics = []
for i in range(9):
    filename = 'woman_' + str(i) + '.gif'
    Pics.append(PhotoImage(file=filename))  # 图片填入Pics列表中,PhotoImage的图片检查只看图片本身的类型,与图片名称后缀无关。


class Square:
    def __init__(self, orderID):
        self.orderID = orderID  # orderID是每个图像块对应的编号

    def draw(self, canvas, board_pos):
        img = Pics[self.orderID]  # 根据编号对应图片
        canvas.create_image(board_pos, image=img)  # draw函数根据board_pos位置画出对应的图片


def init_board():
    L = list(range(9))  # [0,1,2,3,4,5,6,7,8]
    random.shuffle(L)
    for i in range(ROWS):
        for j in range(COLS):
            idx = i * ROWS + j  # 0~2,3~5,6~8
            orderID = L[idx]  # 获得L值
            if orderID == 8:
                board[i][j] = None  # 8序号时不画
            else:
                board[i][j] = Square(orderID)  # 画出图块,效果为随机块


def drawBoard(canvas):
    canvas.create_polygon((0, 0, WIDTH, 0, WIDTH, HEIGHT, 0, HEIGHT), width=1, outline='Black')  # 绘制边框
    for i in range(ROWS):
        for j in range(COLS):
            if board[i][j] is not None:
                board[i][j].draw(canvas, (IMAGE_WIDTH * (j + 0.5), IMAGE_HEIGHT * (i + 0.5)))  # 对每个图像块画边框


def mouseclick(pos):
    """定义图像块被点击后的事件"""
    global steps
    r = int(pos.y // IMAGE_HEIGHT)
    c = int(pos.x // IMAGE_WIDTH)  # r,c为棋盘坐标
    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 + 1] is 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 - 1] is None:  # 左边空
                board[r][c] = None
                board[r][c - 1] = current_square
                steps += 1
            label1['text'] = '步数:' + str(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] is not None and board[i][j].orderID != i * ROWS + j:
                return False  # 如果不是有序的,返回False
    return True


def play_game():
    global steps
    steps = 0
    init_board()


def callback2():
    print('重新开始')
    play_game()
    cv.delete('all')
    drawBoard(cv)


cv = Canvas(root, bg='green', width=WIDTH, height=HEIGHT)
b1 = ttk.Button(root, text='重新开始', command=callback2, width=20)
label1 = Label(root, text='步数:' + str(steps), fg='red', width=20)
label1.pack()
cv.bind('<Button-1>', mouseclick)
# cv.find()
cv.pack()
b1.pack()
play_game()
drawBoard(cv)
root.mainloop()