1

background

Use QGraphicsItem of Qt5.12.9 to implement Tetris, and use a simple evaluation function to implement AI robots to play Tetris games. This is the first step of the AI robot. This algorithm is simple but effective. In most cases, it can eliminate more than 500 layers. In the few recent tests, the highest record has eliminated more than 2500 layers. On this basis, it is convenient to accumulate raw data. I hope to extract patterns, perform pattern recognition and machine learning.

Ideas

Remodeling on the basis of manual games, learning from the experience of playback, only needs to add an evaluation algorithm to find a placement posture (number of rotations) and final position coordinates for each new square. My algorithm design is also very simple, that is, to exhaust the placement method for each square, use a tightness evaluation algorithm to score, and take out the operation with the highest score. If there is an operation with the same score, use a random number two to one to make five. .

Effect picture

Key code analysis

Process control

The interface operation controls variables, so that you can switch between manual and automatic modes at any time.

    if (isAutoRunning) {                //自动模式
        autoProcessCurBlock();            //处理当前方块,使用评估函数确定方块的最终姿态与位置
        block->relocate(curPos);            //放置
        block->setBlockNotActive();        //固定方块
        generateNextBlock();            //取下一个方块,游戏继续
    }else                        //手动模式
        this->moveBlockDown();
    ...

Cube placement scoring function

My design idea is very intuitive. Tetris is to be stacked together as closely as possible, so for each block that makes up a block, four locations around it are checked to see if there is a block (including the border), and if so, add it. 1 point, no extra points. The bonus points of this block do not distinguish between the blocks that make up the block itself and the external blocks. Because each block is compared with itself, the effect of distinguishing and not distinguishing is the same. The starting point is determined by the depth, the deeper I think the better the effect. On the other hand, it is best not to have holes in the vertical bottom of the block, if there are any holes, points will be reduced.

int Game::evaluate(Tetris* t)
{
    QPoint pos = t->getPos();
    int ct = pos.y();                //深度为基础分
    int cct = t->cleanCount();
    if (cct > 1)                //能消层,加分
        ct += 10 * (cct - 1);
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            if (t->data[i][j]) {
                ct += t->hasTetrisBlock(pos.x() + j + 1, pos.y() + i) ? 1 : 0;            //检测block右边的位置
                ct += t->hasTetrisBlock(pos.x() + j - 1, pos.y() + i) ? 1 : 0;            //检测block左边的位置
                ct += t->hasTetrisBlock(pos.x() + j, pos.y() + i + 1) ? 1 : 0;            //检测block下方的位置
                ct += t->hasTetrisBlock(pos.x() + j, pos.y() + i - 1) ? 1 : 0;            //检测block上方的位置

                if (i == 3 || t->data[i + 1][j] == 0) {                    
                    if (!t->hasTetrisBlock(pos.x() + j, pos.y() + i + 1)) {            //block下方的紧临空洞
                        ct -= 4;
                    }
                    else {
                        int k = 2;
                        while (pos.y() + i + k <= 19) {
                            if (!t->hasTetrisBlock(pos.x(), pos.y() + i + k)) {    //block下方的非紧临空洞
                                ct -= 1;
                                break;
                            }
                            k++;
                        }
                    }
                }
            }
        }
    }
    return ct;
}

Exhaustive list of all placement methods

There are at most four poses for a block. Move DownEnd from left to right for each pose of the block once to score and get the highest score.

void Game::autoProcessCurBlock()
{
    int max = 0;
    QPoint initPos = block->getPos();
    Tetris* tmp = new Tetris(initPos, block->getShape(), -1);        //构造当前方块的替身,blockType为-1,这种方块不会显示
    int rotateCt = block->getRotateNum();                //同步替身初始姿态
    for (int k = 0; k < rotateCt; k++)
        tmp->rotate();
    rotateCt = 0;                            //用于保存方块的最终姿态

    for (int r = 0; r < 4; r++) {                    //四种姿态遍历,其实可以优化,有的方块不需要四次
        if (r > 0) {
            tmp->relocate(initPos);                //注意,旋转要在方块进入游戏界面的地方旋转,不然可能旋转不成功
            tmp->rotate();
        }
        while (tmp->moveLeft());                //从最左边开始
        do {
            tmp->moveDownEnd();
            tmp->setBlockNotActive();            //固定方块,以便进行评分
            int score = evaluate(tmp);            //评分
            if (score > max) {                //找到当前最优方案
                max = score;
                curPos = tmp->getPos();
                rotateCt = r;
            }
            else if (score == max) {                //出现相等评分,随机取
                if (qrand() % 2 == 1) {
                    curPos = tmp->getPos();
                    rotateCt = r;
                }
            }
            //initPos.setX(tmp->getPos().x());
            tmp->relocate(QPoint(tmp->getPos().x(), initPos.y()));    //返回到游戏空间上方
            tmp->setBlockTest();                //方块恢复到测试状态 
        } while (tmp->moveRight());                //方块右移,直到不能移动 
    }
    delete tmp;                            //销毁测试方块,突然想到这块可以优化,只需要建七个方块就好,这样就不用不断的创建和销毁了
    for (int k = 0; k < rotateCt; k++)
        block->rotate();
}

The next step

Use python to re-implement all functions, and no longer use Qt, just use python's own tkinter. Focus on the mode extraction, let the AI play the game automatically, write an algorithm, and extract the excellent operation mode. Then use pattern matching or machine learning algorithms to optimize AI. There is no concrete idea yet, only such a general idea.

Source code and operation method

The project is organized by cmake, please install cmake 3.10 or above. The following script is based on MSVC under Windows, and is basically similar on other operating systems, or use qtcreator to open and operate.

cmake -A win32 -Bbuild .
cd build
cmake --build . --config Release

Note: This project can run cross-platform and has been adapted to windows, linux, mac.

Source code:

https://gitee.com/zhoutk/qtetris.git

or

https://gitee.com/zhoutk/qtdemo/tree/master/tetrisGraphicsItem

or

https://github.com/zhoutk/qtDemo/tree/master/tetrisGraphicsItem

zhoutk
2.6k 声望1.2k 粉丝

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