系列文章入口

《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