把俄罗斯方块用 C++ 类重新组织:Board 类管棋盘与消行,Piece 类管当前方块。控制台渲染,每按一次键走一步,逻辑完整可跑。

1. 用类组织:Board 与 Piece

Board 持有 10×20 棋盘和消行逻辑;Piece 持有当前方块矩阵和位置。两者各司其职,主函数只做"读键→尝试移动→渲染":

#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
using namespace std;

class Board {
    vector<vector<int> > g;
public:
    Board() : g(20, vector<int>(10, 0)) {}
    bool canPlace(const vector<vector<int> > &p, int r, int c) {
        for (int i = 0; i < (int)p.size(); i++)
            for (int j = 0; j < (int)p[0].size(); j++)
                if (p[i][j]) {
                    int rr = r + i, cc = c + j;
                    if (rr < 0 || rr >= 20 || cc < 0 || cc >= 10 || g[rr][cc]) return false;
                }
        return true;
    }
    void lock(const vector<vector<int> > &p, int r, int c) {
        for (int i = 0; i < (int)p.size(); i++)
            for (int j = 0; j < (int)p[0].size(); j++)
                if (p[i][j]) g[r + i][c + j] = 1;
    }
    int clearLines() {
        int n = 0;
        for (int r = 19; r >= 0; r--) {
            bool full = true;
            for (int c = 0; c < 10; c++) if (!g[r][c]) full = false;
            if (full) {
                g.erase(g.begin() + r);
                g.insert(g.begin(), vector<int>(10, 0));
                n++; r++;
            }
        }
        return n;
    }
    int at(int r, int c) const { return g[r][c]; }
};

2. 七种方块与旋转

方块矩阵存进静态表,旋转用"转置+反转":

vector<vector<int> > SHAPES[7] = {
    {{1,1,1,1}}, {{1,1},{1,1}},
    {{0,1,0},{1,1,1}}, {{0,1,1},{1,1,0}},
    {{1,1,0},{0,1,1}}, {{1,0,0},{1,1,1}},
    {{0,0,1},{1,1,1}},
};

vector<vector<int> > rotateClock(vector<vector<int> > m) {
    vector<vector<int> > r(m[0].size(), vector<int>(m.size()));
    for (int i = 0; i < (int)m.size(); i++)
        for (int j = 0; j < (int)m[0].size(); j++)
            r[j][m.size() - 1 - i] = m[i][j];
    return r;
}

3. 完整代码

#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
using namespace std;

class Board {
    vector<vector<int> > g;
public:
    Board() : g(20, vector<int>(10, 0)) {}
    bool canPlace(const vector<vector<int> > &p, int r, int c) {
        for (int i = 0; i < (int)p.size(); i++)
            for (int j = 0; j < (int)p[0].size(); j++)
                if (p[i][j]) {
                    int rr = r + i, cc = c + j;
                    if (rr < 0 || rr >= 20 || cc < 0 || cc >= 10 || g[rr][cc]) return false;
                }
        return true;
    }
    void lock(const vector<vector<int> > &p, int r, int c) {
        for (int i = 0; i < (int)p.size(); i++)
            for (int j = 0; j < (int)p[0].size(); j++)
                if (p[i][j]) g[r + i][c + j] = 1;
    }
    int clearLines() {
        int n = 0;
        for (int r = 19; r >= 0; r--) {
            bool full = true;
            for (int c = 0; c < 10; c++) if (!g[r][c]) full = false;
            if (full) {
                g.erase(g.begin() + r);
                g.insert(g.begin(), vector<int>(10, 0));
                n++; r++;
            }
        }
        return n;
    }
    int at(int r, int c) const { return g[r][c]; }
};

vector<vector<int> > SHAPES[7] = {
    {{1,1,1,1}}, {{1,1},{1,1}},
    {{0,1,0},{1,1,1}}, {{0,1,1},{1,1,0}},
    {{1,1,0},{0,1,1}}, {{1,0,0},{1,1,1}},
    {{0,0,1},{1,1,1}},
};

vector<vector<int> > rotateClock(vector<vector<int> > m) {
    vector<vector<int> > r(m[0].size(), vector<int>(m.size()));
    for (int i = 0; i < (int)m.size(); i++)
        for (int j = 0; j < (int)m[0].size(); j++)
            r[j][m.size() - 1 - i] = m[i][j];
    return r;
}

int main() {
    srand((unsigned)time(NULL));
    Board board;
    int score = 0;
    vector<vector<int> > cur = SHAPES[rand() % 7];
    int r = 0, c = 3;
    char key;
    while (true) {
        system("clear");   // Windows: system("cls")
        for (int y = 0; y < 20; y++) {
            for (int x = 0; x < 10; x++) {
                bool shown = board.at(y, x);
                for (int i = 0; i < (int)cur.size() && !shown; i++)
                    for (int j = 0; j < (int)cur[0].size() && !shown; j++)
                        if (cur[i][j] && y == r + i && x == c + j) shown = true;
                cout << (shown ? "[]" : "  ");
            }
            cout << "|\n";
        }
        cout << "分数 " << score << "  a左 d右 s下 w旋转 空格落底 q退出\n";
        cin >> key;
        if (key == 'q') break;
        if (key == 'a' && board.canPlace(cur, r, c - 1)) c--;
        if (key == 'd' && board.canPlace(cur, r, c + 1)) c++;
        if (key == 's' && board.canPlace(cur, r + 1, c)) r++;
        if (key == 'w') {
            vector<vector<int> > m = rotateClock(cur);
            if (board.canPlace(m, r, c)) cur = m;
        }
        if (key == ' ') while (board.canPlace(cur, r + 1, c)) r++;
        if (!board.canPlace(cur, r + 1, c)) {
            board.lock(cur, r, c);
            int n = board.clearLines();
            score += n * 100;
            cur = SHAPES[rand() % 7];
            r = 0; c = 3;
            if (!board.canPlace(cur, r, c)) { cout << "游戏结束,分数 " << score << "\n"; break; }
        }
    }
    return 0;
}

4. 运行与常见问题

保存为 tetris.cpp,g++ tetris.cpp -o tetris 后运行。常见问题:①vector<vector<int>> 初始化——花括号初始化在 C++11 起可用;②O 方块旋转变大——O 只有 2×2,旋转后 canPlace 不通过就保持原状;③消行计数——clearLines 从下往上扫才能连续消。

💡 改进方向:①自动下落;②下一块预览;③幽灵块;④最高分存档;⑤踢墙旋转。