# ===== CodeLab: C++ 小游戏⑧:俄罗斯方块(控制台) =====
# 来源: https://aoerliang.dpdns.org/articles/game-cpp-tetris
# 以下代码片段按文章出现顺序拼接, 共 3 段

# ----- 片段 1 (cpp) -----
#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 (cpp) -----
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 (cpp) -----
#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;
}
