用python编写的45行精简版俄罗斯方块游戏

    技术2022-07-10  135

    我以前用js写过一个60行代码的俄罗斯方块,现在python比较流行,决定再写一个python版本的。 游戏算法与之前的基本一致,也是用二进制作为点阵图数据,用位运算的“与”来判断方块与场地是否重叠,用位运算的“或”来把方块与场地合并。 这次重新优化了程序,并改良了之前不那么优雅的语法。 本想用python编写会超过60行,结果最终优化后的程序不算注释和空行只有45行。

    游戏操作:上键是旋转,左右下键是移动,空格键是暂停,游戏得分显示在标题栏。 由于是精简版,没有下一个方块的提示,也没有级别,方块下落速度随分数加快。

    #-*- coding:utf-8 -*- import random, tkinter, tkinter.messagebox # 7种方块图案(以4*4的16位二进制点阵存储) tetris = (0x66,),(0x2222,0xf0),(0xc60,0x264),(0x6c0,0x462),(0x446,0x2e,0x622,0x74),(0x226,0xe2,0x644,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】俄罗斯方块 作者:jslang" % (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()

    Processed: 0.015, SQL: 9