ZhenghuiLyu

推箱子游戏

首先说明一个概念深拷贝

a=[1,2]
b=a
print(b)
[1, 2]
a.append(3)
print(a)
[1, 2, 3]
print(b)
[1, 2, 3]

用=号连接b和a,b是a的引用,a改变b当然也会结果不同。

对于简单的列表,可以使用切片赋值:

a=[3,4,5]
b=a[:]
a.append(6)
print(a)
[3, 4, 5, 6]
print(b)
[3, 4, 5]

此时a和b无引用关系,a变化不会导致b变化。

但是对于复杂列表如列表嵌套,切片操作同样还是引用:

a=[1,2,3,[4,5,6]]
b=a[:]
a[3].append(7) #子列表[4,5,6]中追加了7
print(a)
[1, 2, 3, [4, 5, 6, 7]]
print(b)
[1, 2, 3, [4, 5, 6, 7]] #b被变化

所以对于复杂列表相互独立,要用到copy模块中的deepcopy()函数。

from copy import deepcopy
a=[1,2,3,[4,5,6]]
b=deepcopy(a)   #b深拷贝了a
a[3].append(7)
print(a)
[1, 2, 3, [4, 5, 6, 7]]  #a子列表追加7
print(b)
[1, 2, 3, [4, 5, 6]]  #b未受到影响

 

推箱子游戏中,在一个7x7的地图上操作,使用myArray二维列表存储状态。0表示墙,1表示人,2表示箱子,3表示路,4表示目的地,5表示此时人站在目的地上,6表示箱子在目的地上,当所有箱子在目的地上时,游戏胜利。

游戏初始状态为:

 

# -*- coding: utf-8 -*-
# @Time : 2020/12/17 14:29
# @Author : Zhenghui Lyu
# @File : Main.py
# @Software: PyCharm

from tkinter import *
from copy import *
from tkinter.messagebox import *

from Myfunction import *

myArray1 = [
    [0, 0, 0, 3, 3, 0, 0],
    [3, 3, 0, 3, 4, 0, 0],
    [1, 3, 3, 2, 3, 3, 0],
    [4, 2, 0, 3, 3, 3, 0],
    [3, 3, 3, 0, 3, 3, 0],
    [3, 3, 3, 0, 0, 3, 0],
    [3, 0, 0, 0, 0, 0, 0]]  # 初始化地图的状态列表

wall = 0  #
worker = 1  #
box = 2  # 箱子
passageway = 3  # 道路
destination = 4  # 目的地
workerindest = 5  # 人站在目的地
redbox = 6  # 箱子到达目的地


def drawgameimage():
    """显示整个游戏图形区域各元素"""
    global x, y, myArray  # 当前工人的坐标,全局变量
    for i in range(0, 7):  # 0-6
        for j in range(0, 7):
            if myArray[i][j] == worker:
                x = i
                y = j  # 寻找当前人物所在位置(x,y)
                print(\'工人当前所在位置为\', x, y)
            img1 = imgs[myArray[i][j]]  # 获取对应的图片文件
            cv.create_image((i * 32 + 20, j * 32 + 20), image=img1)  # 绘制对应图片到画布
            cv.pack()


def isingamearea(row, col):
    """判断工人是否在游戏区域"""
    return 0 <= row < 7 and 0 <= col < 7


def moveman(x, y):
    """移动工人"""
    if myArray[x][y] == worker:  # 如果在普通道路上站
        myArray[x][y] = passageway  # 走后变为普通道路
    elif myArray[x][y] == workerindest:  # 如果当前站在目的地上
        myArray[x][y] = destination  # 走后恢复目的地状态


def isfinish():
    """判断是否过关,箱子都在目的地上,4状态变为6"""
    finish = True  # 默认游戏成功
    for i in range(0, 7):
        for j in range(0, 7):
            if myArray[i][j] == destination or myArray[i][j] == workerindest:
                finish = False
    return finish  # 返回游戏是否过关bool值


def moveto(x1, y1, x2, y2):
    """实现推箱子的逻辑判断"""
    global x, y  # 工人坐标
    P1 = None
    P2 = None  # P1,P2表示移动方向的前两个格子,初始为空值
    if isingamearea(x1, y1):  # 若前面第一个格子在区域中
        P1 = myArray[x1][y1]
    if isingamearea(x2, y2):  # 若前面第二个格子在区域中
        P2 = myArray[x2][y2]
    if P1 == passageway:  # 普通道路
        moveman(x, y)  # 移动工人
        x = x1
        y = y1  # 更新当前工人坐标
        myArray[x1][y1] = worker  # 更新地图,1状态
    if P1 == destination:  # 前方为目的地
        moveman(x, y)  # 移动
        x = x1
        y = y1  # 更新工人坐标
        myArray[x1][y1] = workerindest  # 工人站在目的地上,5状态
    if P1 == wall or not isingamearea(x1, y1):  # P1为墙或者出界
        return  # do nothing
    if P1 == box:  # 前方是箱子,就需要判断P2具体情况
        if P2 == wall or not isingamearea(x1, y1) or P2 == box:  # P2格子出界或是墙,或者也是箱子
            return  # do nothing
    if P1 == box and P2 == passageway:  # P2是道路
        moveman(x, y)
        x = x1
        y = y1
        myArray[x2][y2] = box  # P2改为箱子状态
        myArray[x1][y1] = worker  # P1改为工人状态,原位置状态由moveman()更新
    if P1 == box and P2 == destination:  # P2是目的地
        moveman(x, y)
        x = x1
        y = y1
        myArray[x2][y2] = redbox  # P2状态更改为箱子在目的地的状态6
        myArray[x1][y1] = worker  # 工人此时站在P1
    if P1 == redbox and P2 == passageway:  # P1为目的地上放箱子状态,P2为道路
        moveman(x, y)
        x = x1
        y = y1
        myArray[x2][y2] = box  # 将箱子推离目的地,P2为箱子
        myArray[x1][y1] = workerindest  # P1状态为工人站在目的地上
    if P1 == redbox and P2 == destination:  # P1为箱子在目的地上,P2为另一个目的地
        moveman(x, y)
        x = x1, y = y1
        myArray[x2][y2] = redbox  # P2更新为箱子在目的地上6状态
        myArray[x1][y1] = workerindest  # P1更新为人站在目的地上
    drawgameimage()  # 每移动一次,要重新画出状态图
    if isfinish():  # 每移动一次要判断是否过关
        showinfo(title=\'提示\', message=\'恭喜你,过关了!\')
        print(\'下一关\')


def callback(event):
    """玩家按键处理函数,获取上下左右,"""
    """(x1,y1),(x2,y2)为按键方向的前两个方格"""
    global x, y, myArray  # 工人坐标,地图状态
    print("按下键:", event.char)  # 获取按键内容,char为键盘事件对应的字符代码
    KeyCode = event.keysym  # keysym键盘事件对应的字符串
    print(\'打印KeyCode\', KeyCode)
    if KeyCode == \'Up\':  #
        x1 = x
        y1 = y - 1
        x2 = x
        y2 = y - 2
        moveto(x1, y1, x2, y2)
    elif KeyCode == \'Down\':  #
        x1 = x
        y1 = y + 1
        x2 = x
        y2 = y + 2
        moveto(x1, y1, x2, y2)
    elif KeyCode == \'Left\':  # 左击
        x1 = x - 1
        y1 = y
        x2 = x - 2
        y2 = y
        moveto(x1, y1, x2, y2)
    elif KeyCode == \'Right\':  # 右击
        x1 = x + 1
        y1 = y
        x2 = x + 2
        y2 = y
        moveto(x1, y1, x2, y2)
    elif KeyCode == \'space\':  # 空格键重置游戏
        print(\'按下键:\', event.char)
        myArray = deepcopy(myArray1)  # 深拷贝初始化状态列表到myArray用于操作,原列表myArray1用于重新开始游戏等
        drawgameimage()


if __name__ == \'__main__\':
    root = Tk()
    root.title(\'推箱子游戏(空格键重置)\')
    imgs = [PhotoImage(file=\'wall.gif\'), PhotoImage(file=\'worker.gif\'), PhotoImage(file=\'box.gif\'),
            PhotoImage(file=\'passageway.gif\'), PhotoImage(file=\'destination.gif\'), PhotoImage(file=\'workerindest.gif\'),
            PhotoImage(file=\'redbox.gif\')]  # 对应的图片,使用PhotoImage()前应该声明一个Tk
    cv = Canvas(root, bg=\'green\', width=226, height=226)
    myArray = deepcopy(myArray1)  # 深拷贝初始化状态列表到myArray用于操作,原列表myArray1用于重新开始游戏等
    drawgameimage()
    cv.bind(\'<KeyPress>\', callback)
    cv.pack()
    cv.focus_set()
    root.mainloop()

 

发表于 2020-12-17 15:17  footmark89  阅读(60)  评论(0编辑  收藏  举报
 

分类:

技术点:

相关文章: