Series entry

"Python3 Programming Actual Tetris Robot"

Tetris class

Combine the Block class to realize all operations such as drawing, moving and rotating Tetris. This is the business core of Tetris games. The first step is to realize the requirement of manual play. Later, when AI plays automatically, this category will be transformed. In all the logic, pay special attention to the rotate operation. Many bugs resolved later proved to be caused by incomplete consideration of the rotate operation.

Design ideas

The Tetris class realizes the drawing of the screen by combining the Block class and decouples it from the tkinter library. Because of the design of the tkinter library, our interface uses two Canvas to realize the display of the game space and the next box respectively, so a box may be displayed in a different Canvas. When a block is placed, the next block must be taken out of the nextCanvas and placed above the game space. For this operation, I did not find an easy way to move components across Canvas. My method of implementation is to regenerate a square in the game space the same as in nextCanvas, because the initial shape of each square is fixed, just let it realize a few random rotations, so I only need to query next Tetris The shape and number of rotations can be copied.

Correlation constant

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"
)

Implementation

Constructor

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))

Determine whether there is a block in a certain position of the game space

This function is very important. It is needed to determine whether it is out of bounds and whether the block can move. The game space is a circle larger than the actual space, and the outermost data is initialized to 1, as an out-of-bounds sentry.

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

Determine whether a block (Tetris) can be placed

Move, rotate, and judge whether the game is over

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

Clear box

The clearing operation is done by the combined Block class itself.

def clean(self):
    for block in self.objs:
        block.clean()
    self.objs.clear()

Block redraw

It is used when rotating, because the relocate of the Block class is implemented by tkinter.move, and its parameter is the relative distance. Therefore, the redrawing of the rotation is more troublesome, and I adopted a relatively simple and crude method to achieve it.

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))

Content preview

Move and rotate to the next article.
Because of the problems with tkinter and Timer, after the AI implementation, I found that the program had a serious memory leak problem. This problem tortured me for a while. Please continue to pay attention to what happens, thank you!

project address

https://gitee.com/zhoutk/ptetris
或
https://github.com/zhoutk/ptetris

Operation method

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

Related items

C++ version has been implemented, project address:

https://gitee.com/zhoutk/qtetris

zhoutk
2.6k 声望1.2k 粉丝

自由程序员,技术路线c,delphi,c++,c#,java,php,node.js,python,golang,typescript;超喜欢react.js的设计思路,全栈开发成为我的终极目标。开发机器macbook pro,或装ubuntu、fedora的机器,编程用vim...