乐趣区

关于python3.x:Python3编程实战Tetris机器人Tetris类

系列文章入口

《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)]   # 游戏空间定义 10x20

TETRISAHPES = (                   # 方块的状态定义
    (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, git
2. git clone https://gitee.com/zhoutk/ptetris (or download and unzip source code)
3. cd ptetris
4. python3 tetris

This project surpport windows, linux, macOs

on linux, you must install tkinter first, use this command:  
sudo apt install python3-tk

相干我的项目

曾经实现了 C ++ 版,我的项目地址:

https://gitee.com/zhoutk/qtetris
退出移动版