推箱子游戏
首先说明一个概念深拷贝:
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()