用python写一个2048?你也可以!
这是我今天的学习过程中看到的
代码来源:《Python游戏设计案例实战》
过程很复杂啦,我把源码放在这,具体程序放在GitHub上,想要的点击这里
from msilib.schema import Directory
from tkinter import *
from tkinter import messagebox as msgbox
import random
from tkinter import scrolledtext
from turtle import left
from unittest import result
v = [[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]]
def init(v):
for i in range(4):
v[i] = [random.choice([0,0,0,2,2,4])for x in v[i]]
def align(vList,direction):
'''
对齐非零的数字
direction == 'left':向左对齐,如[8,0,0,2]左对齐后成为[8,2,0,0]
direction == 'right':向右对齐,如[8,0,0,2]左对齐后成为[0,0,8,2]
'''
#移除列表中的0元素
for i in range(vList.count(0)):
vList.remove(0)
#被移除的0元素
zeros = [0 for x in range(4 - len(vList))]
if direction == 'left':
#在右侧补0元素
vList.extend(zeros)
else:
#在左侧补0元素
vList[:0] = zeros
def addSame(vList,direction):
#将相同的元素相加,返回新增积分
score = 0
if direction == 'left':
for i in [0,1,2]:
if vList[i] == vList[i+1] != 0:
vList[i] *= 2
vList[i+1] = 0
score += vList[i]
return {'bool':True,'score':score}
else:
for i in [3,2,1]:
if vList[i] == vList[i-1] != 0:
vList[i] *= 2
vList[i-1] = 0
score += vList[i]
return{'bool':True,'score':score}
return{'bool':False,'score':score}
def handle(vList,direction):
'''
处理一行(列)中的数据,得到最终的该行(列)的数字状态值,返回得分
vList:列表结构,存储了一行(列)中的数据
direction:移动放向,向上和向左都使用方向'left',向右和向下都使用'right'
'''
increment = 0
align(vList,direction)
result = addSame(vList,direction)
#合并的得分
increment += result['score']
align(vList,direction)
return increment
def operation(v,op):
totalScore = 0
#计算本次得分
gameOver = False
direction = 'left'
print(op)
if op == 'Left':
#向左移动
direction = 'left'
for row in range(4):
totalScore += handle(v[row],direction)
elif op == 'Right':
#向右移动
direction = 'right'
for row in range(4):
totalScore += handle(v[row],direction)
elif op == 'Up':
#向上移动
direction = 'left'
for col in range(4):
#将矩阵中一列复制到一个列表中然后处理
vList = [v[row][col]for row in range(4)]
totalScore += handle(vList,direction)
#将处理后的列表中的数字覆盖原来矩阵中的值
for row in range(4):
v[row][col] = vList[row]
elif op == 'Down':
#向下移动
direction = 'right'
for col in range(4):
#将矩阵中一列复制到一个列表中然后处理
vList = [v[row][col]for row in range(4)]
totalScore += handle(vList,direction)
#将处理后的列表中的数字覆盖原来矩阵中的值
for row in range(4):
v[row][col] = vList[row]
#以下是在空白区域随机产生的新的数字
N = 0
for q in v:
#统计0的个数
N += q.count(0)
#统计空白区域数目N
#存在剩余的空白区域时,产生随机数2和4
if N != 0:
addElement(N)
#判断游戏是否真正结束
if isOver():
gameOver = True
return {'gameOver':gameOver,'score':totalScore}
def addElement(N):
#按照数字2和数字4出现的比率为3:1来产生随机数2和4
num = random.choice([2,2,2,4])
#产生随机数K,上一步产生的2或4将被填到第k个空白区域
k = random.randrange(1,N+1)
n = 0
for i in range(4):
for j in range(4):
if v[i][j] == 0:
n += 1
if n == k:
v[i][j] = num
break
def isOver():
N = 0
for q in v:
#统计0的个数
N += q.count(0)
if N != 0:
return False
else:
for row in range(4):
#按行判断是否有相同元素
flag = isListOver(v[row])
if flag ==False:
return False
for col in range(4):
#按列判断是否有相同元素
#将矩阵中的一列复制到一个列表中然后处理
vList = [v[row][col] for row in range(4)]
flag = isListOver(vList)
if flag == False:
return False
return True
def isListOver(vList):
for i in [0,1,2]:
if vList[i] == vList[i+1] and vList[i+1] != 0:
return False
return True
def drawGameImage():
global x,y
for i in range(0,4):
for j in range(0,4):
#计算对应的图像索引号
m = v[i][j]
#二维列表中存储的是2,4,8,需要将其转换成图像索引号
#print('m',m)
n = 0
while m > 1:
n = n + 1
m = m / 2
#print('n',n)
img1 = imgs[n]
#从imgs列表获取对应的图像
cv.create_image((j*120+70,i*120+70),image = img1)
#显示到Canvas上
cv.pack()
def callback(event):
#按键处理
global score
print('按下键:',event.char)
KeyCode = event.keysym
#获取用户按下的方向键
result = operation(v,KeyCode)
#根据移动方向重新计算矩阵值
drawGameImage()
#绘制游戏界面
score += result['score']
#从字典中获取'score'键值
root.title('得分:'+str(score))
if result['gameOver'] == True:
#游戏结束
print('Game Over, You failed!')
msgbox.showinfo('Game Over','Your total score:'+str(score))
else:
if score >= 20480:
print('Game Over, You win!!!')
msgbox.showinfo('Game Over','You Win!!!')
init(v)
score = 0
root = Tk()
root.title('2048')
imgs = [PhotoImage(file=x) for x in ['0.png','2.png','4.png','8.png','16.png','32.png','64.png','128.png','256.png','512.png','1024.png','2048.png','4096.png']]
cv = Canvas(root,bg='green',width = 500,height = 500)
drawGameImage()
cv.bind('<KeyPress>',callback)
cv.pack()
cv.focus_set()
#将焦点设置到cv上
root.mainloop()
如果你觉得我的分享有点意思,或者能给你带来一些收获,那么给我点个赞叭!