系列文章入口
《Python3编程实战Tetris机器人》
Tetris类
组合Block类,实现俄罗斯方块的绘制及挪动、旋转等所有操作。这是Tetris游戏的业务外围,第一步先实现手动玩的需要,当前AI主动玩时,还会革新这个类。在所有的逻辑外面,特地留神旋转(rotate)操作,前面解决的不少的bug被证实都是因为rotate操作思考不全面所引起的。
设计思路
Tetris类通过组合Block类来实现屏幕的绘制,并与tkinter库进行解耦。因为tkinter库的设计,咱们的界面应用了两个Canvas来别离实现游戏空间和下一方块的显示,因而一个方块有可能显示在不同的Canvas中。当一个方块搁置后,要从nextCanvas中取出下一个方块,搁置到游戏空间的上方。这个操作我没有找到简略的办法来施行跨Canvas挪动元件。我的实现办法是,从新在游戏空间生成一个与nextCanvas中一样的方块,因为我每一个方块的初始状态是固定的,只是让它实现了几次随机的旋转,因而我只需查问next Tetris中的形态和旋转次数就能够复制了。
相干常数
GameRoom = [[0 for i in range(12)] for i in range(22)] # 游戏空间定义 10x20TETRISAHPES = ( # 方块的状态定义 (1, 1, 1, 1), # 方块一共有六种状态 (0, 1, 1, 1, 0, 1), # 其它状态都能够通过几次旋转来失去 (1, 1, 1, 0, 0, 0, 1), # 我定义旋转为顺时针旋转 (0, 1, 1, 0, 0, 1, 1), # 每一个方块的状态最多旋转四次就回到初始状态 (1, 1, 0, 0, 0, 1, 1), (0, 1, 1, 0, 1, 1), (0, 1, 0, 0, 1, 1, 1))TETRISCOLORS = ( # 方块状态与色彩的绑定 "red", "magenta", "darkMagenta", "gray", "darkGreen", "darkCyan", "darkBlue")
具体实现
构造函数
def __init__(self, canvas, x, y, shape): self.x = x # 方块在游戏空间的横坐标地位 1-10 self.y = y # 方块在游戏空间的纵坐标地位 1-20 self.canvas = canvas # 方块绘制的空间 self.objs = [] # 组合Block类对象 self.rotateCount = 0 # 方块旋转次数 self.shape = shape # 方块初始状态 self.color = TETRISCOLORS[shape] # 方块色彩 self.data = [ # 方块状态数据 [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0] ] curShape = TETRISAHPES[shape % len(TETRISAHPES)] for i, b in enumerate(curShape): # 绘制方块初始状态 if b: self.data[1 + i // TETRISDIMENSION][i % TETRISDIMENSION] = 1 # 状态数据初始化 self.objs.append(Block(canvas, self.x + i % TETRISDIMENSION, \ # 组合Block并绘制 self.y + 1 + i // TETRISDIMENSION, self.color))
判断游戏空间某个地位是否有Block
这个函数很重要,判断是否越界、方块是否能挪动都须要它。游戏空间比理论空间大一圈,最外围数据都初始化为1,作为越界哨兵。
def hasBlock(self, x, y): if x < 1 or x > 10 or y > 20: return True if GameRoom[y][x] == 1: return True else: return False
判断一个方块(Tetris)是否能搁置
挪动、旋转以及游戏是否完结的判断都要用到
def canPlace(self, x, y): for i in range(TETRISDIMENSION): for j in range(TETRISDIMENSION): if self.data[i][j] and GameRoom[y + i][x + j]: return False return True
革除方块
革除操作由组合的Block类自行实现。
def clean(self): for block in self.objs: block.clean() self.objs.clear()
方块重绘
旋转的时候应用,因为Block类的relocate应用是tkinter.move来实现的,而它的参数是绝对间隔。因而旋转的重绘比拟麻烦,我采纳了绝对简略粗犷的办法来实现。
def redraw(self): self.clean() # 整体革除 for i in range(TETRISDIMENSION): # 生成全新Tetris for j in range(TETRISDIMENSION): # 办法很简略、无效 if self.data[i][j]: # 但因为tkinter的问题,起初发现它加剧了内存透露问题 self.objs.append(Block(self.canvas, self.x + j, self.y + i, self.color))
内容预报
挪动和旋转放到下一篇中。
因为tkinter和Timer的问题,前面在AI实现后,发现程序有重大的内存透露问题,这个问题把我好一阵折磨,欲后事如何,请继续关注,谢谢!
我的项目地址
https://gitee.com/zhoutk/ptetris或https://github.com/zhoutk/ptetris
运行办法
1. install python3, git2. git clone https://gitee.com/zhoutk/ptetris (or download and unzip source code)3. cd ptetris4. python3 tetrisThis project surpport windows, linux, macOson linux, you must install tkinter first, use this command: sudo apt install python3-tk
相干我的项目
曾经实现了C++版,我的项目地址:
https://gitee.com/zhoutk/qtetris