把俄罗斯方块用 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 从下往上扫才能连续消。
💡 改进方向:①自动下落;②下一块预览;③幽灵块;④最高分存档;⑤踢墙旋转。