用户:
笑颜crazy查看:0 回复:0 评论:0 创建时间:2020-11-20T21:57:18
#-*- coding:utf-8 -*-
import random
import tkinter
import tkinter.messagebox
# 7种方块图案(以4*4的16位二进制点阵存储)
tetris = (0x66,), (0x2222, 0xf0), (0xc60, 0x2喵), (0x6c0, 0x462), (0x446,
0x2e, 0x622, 0x74), (0x226, 0xe2, 0x喵4, 0x470), (0x262, 0x72, 0x232, 0x270)
# 游戏场地数据 (以每行12位二进制点阵存储,底线设置两行是为了防止计算时列表索引越界)
fie = [0x801]*25+[0x7fe]*2
# 游戏运行需要的数据
p = {"pause": True, "lines": 0}
# 将012字符映射成空格,实心方块与空心方块的转换表
mak = str.maketrans("012", "\u3000\u25a0\u25a1")
# 初始化新方块函数
def init():
# 为了方便在标题栏显示分数
win.title("【分数:%d】俄罗斯方块 作者:知足" % (p["lines"]*100))
# 初始化新方块的数据 dia是随机选择出的一种方块图案,r是方块图案旋转的次数,x和y是方块位置坐标
p.update(dia=random.choice(tetris),
r=random.randrange(4), y=0, x=8, pause=False)
# 动作函数 e是操作的属性名,v是对属性增减的数值
def act(e, v):
# 如果是暂停状态则退出函数
if p["pause"]:
return
# 对操作的属性增减
p[e] += v
# 取得当前旋转的方块图案
h = p['dia'][p['r'] % len(p['dia'])]
# 将4*4的16位二进制点阵转换成4行每行12位二进制点阵
f = {i: (h << i*4 & 0xf000) >> p['x'] for i in range(4)}
# 用位运算的“与”来判断方块与场地是否重叠
if all(map(lambda i: f[i] & fie[p['y']+i] == 0, f)):
# 将二进制数据转换成方块字符并显示
box['text'] = '\n'.join(str(int(bin(fie[i])[
2:])+int(bin(f.get(i-p['y'], 0))[2:])*2)[1:-1] for i in range(4, 25)).translate(mak)
return True
# 解决方块处于左右边缘无法旋转的问题
if e != 'r' or not(act('x', -1) or act('x', 1) or act('x', 2)):
# 对之前的属性增减反向操作,等于撤销之前的操作
p[e] -= v
# 判断方块已到底部
if e == 'y':
for i in f:
# 用位运算的“或”来把方块与场地合并
fie[p['y']+i] |= f[i]
# 如果一行已填满,则删除这一行并在列表头添加新行
if fie[p['y']+i] == 0xfff:
del fie[p['y']+i]
fie.insert(0, 0x801)
p["lines"] += 1
# 判断游戏结束
if fie[3] != 0x801:
p.update(pause=True, lines=0)
fie[:25] = [0x801]*25
if not tkinter.messagebox.askyesno("游戏结束", "方块到顶了,要重新再来一局吗"):
win.quit()
init()
# 定时器函数
def timeout():
# 方块下落一行
act('y', 1)
# 间隔一定的时间再次调用本函数
win.after(300-p["lines"]*3, timeout)
# 创建游戏窗口和组件
win = tkinter.Tk()
box = tkinter.Label(win, font=("\u5B8B\u4F53", 28), fg="#fc9", bg="#024")
box.pack()
# 绑定键盘事件,上键是旋转,左右下键是移动,空格键是暂停
win.bind('<Up>', lambda e: act('r', 1))
win.bind('<Down>', lambda e: act('y', 1))
win.bind('<Left>', lambda e: act('x', -1))
win.bind('<Right>', lambda e: act('x', 1))
win.bind('<space>', lambda e: p.update(pause=not p["pause"]))
init()
timeout()
# 进入窗口消息循环
win.mainloop()