猫史档案馆


献出俄罗斯方块

用户:笑颜crazy笑颜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()


回复

上一页1 页 / 共 0下一页