Previous question:Text-based Tetris gameI don't have a Linux terminal to be sure whether or not I have implemented the Linux version correctly, but hopefully it's OK. Summary of improvements:More OOP Improved the names of the classes and their functions and I hope they're OK nowMore portable, isolated platform-specific codeEliminated magic numbersI would like to know if there is anything I should take care of before processing the code.#include <iomanip>#include <iostream>#include <vector>#include <random>#ifdef __linux__ /*****************************************************************************kbhit() and getch() for Linux/UNIXChris Giese <geezer@execpc.com> http://my.execpc.com/~geezerRelease date: ?This code is public domain (no copyright).You can do whatever you want with it.****************************************************************************/#include <sys/time.h> /* struct timeval, select() *//* ICANON, ECHO, TCSANOW, struct termios */#include <termios.h> /* tcgetattr(), tcsetattr() */#include <stdlib.h> /* atexit(), exit() */#include <unistd.h> /* read() */#include <stdio.h> /* printf() */static struct termios g_old_kbd_mode;/**********************************************************************************************************************************************************/static void cooked(void){    tcsetattr(0, TCSANOW, &g_old_kbd_mode);}/**********************************************************************************************************************************************************/static void raw(void){    static char init;    /**/    struct termios new_kbd_mode;    if (init)        return;    /* put keyboard (stdin, actually) in raw, unbuffered mode */    tcgetattr(0, &g_old_kbd_mode);    memcpy(&new_kbd_mode, &g_old_kbd_mode, sizeof(struct termios));    new_kbd_mode.c_lflag &= ~(ICANON | ECHO);    new_kbd_mode.c_cc[VTIME] = 0;    new_kbd_mode.c_cc[VMIN] = 1;    tcsetattr(0, TCSANOW, &new_kbd_mode);    /* when we exit, go back to normal, cooked mode */    atexit(cooked);    init = 1;}/**********************************************************************************************************************************************************/static int _kbhit(void){    struct timeval timeout;    fd_set read_handles;    int status;    raw();    /* check stdin (fd 0) for activity */    FD_ZERO(&read_handles);    FD_SET(0, &read_handles);    timeout.tv_sec = timeout.tv_usec = 0;    status = select(0 + 1, &read_handles, NULL, NULL, &timeout);    if (status < 0)    {        printf(select() failed in kbhit()\n);        exit(1);    }    return status;}/**********************************************************************************************************************************************************/static int _getch(void){    unsigned char temp;    raw();    /* stdin = fd 0 */    if (read(0, &temp, 1) != 1)        return 0;    return temp;}struct COORD { short X; short Y; };bool gotoxy(unsigned short x = 1, unsigned short y = 1) {    if ((x == 0) || (y == 0))        return false;    std::cout << \x1B[ << y << ; << x << H;}void clearScreen(bool moveToStart = true) {    std::cout << \x1B[2J;    if (moveToStart)        gotoxy(1, 1);}inlinevoid print(std::string& str, COORD& coord){    gotoxy(coord.X, coord.Y);    std::cout << str << std::flush;;}inlinevoid print(TCHAR* str, COORD& coord){    gotoxy(coord.X, coord.Y);    std::cout << str << std::flush;;}inlinevoid print(TCHAR& c, COORD& coord){    gotoxy(coord.X, coord.Y);    std::cout << c << std::flush;}#elif _WIN32#include <conio.h> /* kbhit(), getch() */#include <Windows.h>#include <tchar.h>void clearScreen(){    HANDLE                     hStdOut;    CONSOLE_SCREEN_BUFFER_INFO csbi;    DWORD                      count;    DWORD                      cellCount;    COORD                      homeCoords = { 0, 0 };    hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);    if (hStdOut == INVALID_HANDLE_VALUE) return;    if (!GetConsoleScreenBufferInfo(hStdOut, &csbi)) return;    cellCount = csbi.dwSize.X *csbi.dwSize.Y;    if (!FillConsoleOutputCharacter(        hStdOut,        (TCHAR) ' ',        cellCount,        homeCoords,        &count        )) return;    if (!FillConsoleOutputAttribute(        hStdOut,        csbi.wAttributes,        cellCount,        homeCoords,        &count        )) return;    /* Move the cursor home */    SetConsoleCursorPosition(hStdOut, homeCoords);}void gotoxy(int x, int y){    COORD coord;    coord.X = x;    coord.Y = y;    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);}static CONSOLE_SCREEN_BUFFER_INFO csbi;COORD getXY(){    GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);    COORD position;    position.X = csbi.dwCursorPosition.X;    position.Y = csbi.dwCursorPosition.Y;    return position;}static DWORD cCharsWritten = 0;inlinevoid print(std::string& str, COORD& coord){    WriteConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), str.c_str(), str.length(), coord, &cCharsWritten);}inlinevoid print(TCHAR* str, COORD& coord){    WriteConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), str, _tcslen(str), coord, &cCharsWritten);}inlinevoid print(TCHAR& c, COORD& coord){    FillConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), c, 1, coord, &cCharsWritten);}#else#error OS not supported!#endifstatic std::vector<std::vector<std::vector<int>>> block_list ={    {        { 0, 1, 0, 0 },        { 0, 1, 0, 0 },        { 0, 1, 0, 0 },        { 0, 1, 0, 0 }    },    {        { 0, 0, 0, 0 },        { 0, 1, 1, 0 },        { 0, 1, 0, 0 },        { 0, 1, 0, 0 }    },    {        { 0, 0, 1, 0 },        { 0, 1, 1, 0 },        { 0, 1, 0, 0 },        { 0, 0, 0, 0 }    },    {        { 0, 1, 0, 0 },        { 0, 1, 1, 0 },        { 0, 0, 1, 0 },        { 0, 0, 0, 0 }    },    {        { 0, 0, 0, 0 },        { 0, 1, 0, 0 },        { 1, 1, 1, 0 },        { 0, 0, 0, 0 }    },    {        { 0, 0, 0, 0 },        { 0, 1, 1, 0 },        { 0, 1, 1, 0 },        { 0, 0, 0, 0 }    },    {        { 0, 0, 0, 0 },        { 0, 1, 1, 0 },        { 0, 0, 1, 0 },        { 0, 0, 1, 0 }    }};struct NonCopyable{    NonCopyable() = default;    NonCopyable(const NonCopyable &) = delete;    NonCopyable(const NonCopyable &&) = delete;    NonCopyable& operator = (const NonCopyable&) = delete;};struct Random : public NonCopyable{    Random(int min, int max)        : mUniformDistribution(min, max)    {}    int operator()()    {        return mUniformDistribution(mEngine);    }    std::default_random_engine mEngine{ std::random_device()() };    std::uniform_int_distribution<int> mUniformDistribution;};struct Block : public NonCopyable{    static const int ROTATIONS_IN_CIRCLE = 4;    int rotation_count = 0;    COORD coord;    std::vector<std::vector<int>> block;    Block()    {        block.resize(4, std::vector<int>(4, 0));        coord.X = 0;        coord.Y = 0;    }    void rotate()    {        ++rotation_count;        while (rotation_count > ROTATIONS_IN_CIRCLE)        {            rotation_count -= ROTATIONS_IN_CIRCLE;        }    }    int& getDim(int row, int column)    {        switch (rotation_count % ROTATIONS_IN_CIRCLE)        {        default:            return block[row][column];        case 1:            return block[block.size() - column - 1][row];        case 2:            return block[block.size() - row - 1][block.size() - column - 1];        case 3:            return block[column][block.size() - row - 1];        }    }    size_t size()    {        return block.size();    }};struct Board : public NonCopyable{    Board()    {        field.resize(22, std::vector<int>(13, 0));        coord.X = 0;        coord.Y = 0;    }    COORD coord;    std::vector<std::vector<int>> field;    int& getDim(int row, int column)    {        return field[row][column];    }    size_t size() const    {        return field.size();    }    size_t rowSize() const    {        return field[0].size();    }};struct Collidable : public NonCopyable{    Collidable()    {        stage.resize(22, std::vector<int>(13, 0));        coord.X = 0;        coord.Y = 0;    }    COORD coord;    int& getDim(int row, int column)    {        return stage[row][column];    }    size_t size() const    {        return stage.size();    }    size_t rowSize() const    {        return stage[0].size();    }    std::vector<std::vector<int>> stage;};class Tetris : public NonCopyable{public:    Tetris()         : board(), block(), stage()    {};    bool makeBlocks();    void initField();    void moveBlock(int, int);    void collidable();    bool isCollide(int, int);    void userInput();    bool rotateBlock();    void spawnBlock();    virtual void display(){};    virtual void GameOverScreen() {};protected:    int y = 0;    int x = 4;    bool gameOver = false;    Board board;    Block block;    Collidable stage;    Random getRandom{ 0, 6 };};void Tetris::initField(){    for (size_t i = 0; i <= board.size() - 2; ++i)    {        for (size_t j = 0; j <= board.rowSize() - 2; ++j)        {            if ((j == 0) || (j == 11) || (i == 20))            {                board.getDim(i, j) = stage.getDim(i, j) = 9;            }            else            {                board.getDim(i, j) = stage.getDim(i, j) = 0;            }        }    }    makeBlocks();    display();}bool Tetris::makeBlocks(){    x = 4;    y = 0;    int blockType = getRandom();    for (size_t i = 0; i < block.size(); ++i)    {        for (size_t j = 0; j < block.size(); ++j)        {            block.getDim(i, j) = 0;            block.getDim(i, j) = block_list[blockType][i][j];        }    }    for (size_t i = 0; i < block.size(); i++)    {        for (size_t j = 0; j < block.size(); j++)        {            board.getDim(i, j + block.size()) = stage.getDim(i, j + block.size()) + block.getDim(i, j);            if (board.getDim(i, j + block.size()) > 1)            {                gameOver = true;                return true;            }        }    }    return false;}void Tetris::moveBlock(int x2, int y2){    //Remove block    for (size_t i = 0; i < block.size(); ++i)    {        for (size_t j = 0; j < block.size(); ++j)        {            board.getDim(y + i, x + j) -= block.getDim(i, j);        }    }    //Update coordinates    x = x2;    y = y2;    // assign a block with the updated value    for (size_t i = 0; i < block.size(); ++i)    {        for (size_t j = 0; j < block.size(); ++j)        {            board.getDim(y + i, x + j) += block.getDim(i, j);        }    }    display();}void Tetris::collidable(){    for (size_t i = 0; i < stage.size(); ++i)    {        for (size_t j = 0; j < stage.rowSize(); ++j)        {            stage.getDim(i, j) = board.getDim(i, j);        }    }}bool Tetris::isCollide(int x2, int y2){    for (size_t i = 0; i < block.size(); ++i)    {        for (size_t j = 0; j < block.size(); ++j)        {            if (block.getDim(i, j) && stage.getDim(y2 + i, x2 + j) != 0)            {                return true;            }        }    }    return false;}void Tetris::userInput(){    char key;    key = _getch();    switch (key)    {    case 'd':        if (!isCollide(x + 1, y))        {            moveBlock(x + 1, y);        }        break;    case 'a':        if (!isCollide(x - 1, y))        {            moveBlock(x - 1, y);        }        break;    case 's':        if (!isCollide(x, y + 1))        {            moveBlock(x, y + 1);        }        break;    case ' ':        rotateBlock();    }}bool Tetris::rotateBlock(){    std::vector<std::vector<int>> tmp(block.size(), std::vector<int>(block.size(), 0));    for (size_t i = 0; i < tmp.size(); ++i)    {        for (size_t j = 0; j < tmp.size(); ++j)        {            tmp[i][j] = block.getDim(i, j);        }    }    for (size_t i = 0; i < block.size(); ++i)    { //Rotate        for (size_t j = 0; j < block.size(); ++j)        {            block.getDim(i, j) = tmp[block.size() - 1 - j][i];        }    }    if (isCollide(x, y))    { // And stop if it overlaps not be rotated        for (size_t i = 0; i < block.size(); ++i)        {            for (size_t j = 0; j < block.size(); ++j)            {                block.getDim(i, j) = tmp[i][j];            }        }        return true;    }    for (size_t i = 0; i < block.size(); ++i)    {        for (size_t j = 0; j < block.size(); ++j)        {            board.getDim(y + i, x + j) -= tmp[i][j];            board.getDim(y + i, x + j) += block.getDim(i, j);        }    }    display();    return false;}void Tetris::spawnBlock(){    if (!isCollide(x, y + 1))    {        moveBlock(x, y + 1);    }    else    {        collidable();        makeBlocks();        display();    }}class Game : public Tetris{public:    Game() = default;    int menu();    virtual void gameOverScreen();    void gameLoop();    virtual void display();    void introScreen();private:    size_t GAMESPEED = 20000;};void Game::gameOverScreen(){    COORD coord = { 0, 0 };    coord.Y++;    print( #####     #    #     # ####### ####### #     # ####### ######, coord);    coord.Y++;    print(#     #   # #   ##   ## #       #     # #     # #       #     #, coord);    coord.Y++;    print(#        #   #  # # # # #       #     # #     # #       #     #, coord);    coord.Y++;    print(#  #### #     # #  #  # #####   #     # #     # #####   ######, coord);    coord.Y++;    print(#     # ####### #     # #       #     #  #   #  #       #   #, coord);    coord.Y++;    print(#     # #     # #     # #       #     #   # #   #       #    #, coord);    coord.Y++;    print( #####  #     # #     # ####### #######    #    ####### #     #, coord);    coord.Y += 2;    print(Press any key and enter, coord);    char a;    std::cin >> a;}void Game::gameLoop(){    size_t time = 0;    initField();    while (!gameOver)    {        if (_kbhit())        {            userInput();        }        if (time < GAMESPEED)        {            time++;        }        else        {            spawnBlock();            time = 0;        }    }}int Game::menu(){    introScreen();    int select_num = 0;    std::cin >> select_num;    switch (select_num)    {    case 1:    case 2:    case 3:        break;    default:        select_num = 0;        break;    }    return select_num;}void Game::introScreen(){    clearScreen();    COORD coord = { 0, 0 };    print(#==============================================================================#, coord);    coord.Y++;    print(####### ####### ####### ######    ###    #####, coord);    coord.Y++;    print(   #    #          #    #     #    #    #     #, coord);    coord.Y++;    print(   #    #          #    #     #    #    #, coord);    coord.Y++;    print(   #    #####      #    ######     #     #####, coord);    coord.Y++;    print(   #    #          #    #   #      #          #, coord);    coord.Y++;    print(   #    #          #    #    #     #    #     #, coord);    coord.Y++;    print(   #    #######    #    #     #   ###    #####          made for fun , coord);    coord.Y += 4;    coord.Y++;    print(     <Menu>, coord);    coord.Y++;    print(     1: Start Game, coord);    coord.Y++;    print(     2: Quit, coord);    coord.Y += 2;    print(#==============================================================================#, coord);    coord.Y++;    print(Choose >> , coord);    coord.X = strlen(Choose >> );    gotoxy(coord.X, coord.Y);}void Game::display(){    clearScreen();    for (size_t i = 0; i < board.size(); ++i)    {        for (size_t j = 0; j < board.rowSize(); ++j)        {            switch (board.getDim(i, j))            {            case 0:                std::cout <<   << std::flush;                break;            case 9:                std::cout << @ << std::flush;                break;            default:                std::cout << # << std::flush;                break;            }        }        std::cout << std::endl;    }    COORD coord = { 0, board.size() };    print(     A: left     S: down     D: right            Rotation[Space], coord);    if (gameOver)    {        clearScreen();        gameOverScreen();    }}int main(){    Game game;    switch (game.menu())    {        case 1:            game.gameLoop();            break;        case 2:            return 0;        case 0:            COORD coord = { 20, 20 };            print(Choose 1~2, coord);            return -1;    }    return 0;}
Text-based Tetris game - follow-up
c++;c++11;game;tetris
Just a few quick comments on things I saw when scanning through:struct Block : public NonCopyableBy defining this as a struct, you make members public (unless overridden).  As a general rule, it is preferred for members to be private as a default.  If you are marking a member as public then you should have a specific reason for that member.  That pushes you to write code that does not rely on the members being public.  You do not seem to be publicly using your public members, so you might as well make this a class.  Note:  this is not to say that there is never a reason to use a struct or public member, just that I see no sign of such a reason here.      block.resize(4, std::vector<int>(4, 0));    field.resize(22, std::vector<int>(13, 0));    stage.resize(22, std::vector<int>(13, 0));int x = 4;Random getRandom{ 0, 6 };for (size_t i = 0; i <= board.size() - 2; ++i)    for (size_t j = 0; j <= board.rowSize() - 2; ++j)        if ((j == 0) || (j == 11) || (i == 20))            board.getDim(i, j) = stage.getDim(i, j) = 9;x = 4;        COORD coord = { 20, 20 };There still seem to be a lot of magic numbers in the code.  Some of them are repeated.  Random getRandom{ 0, 6 };could be something like Random getRandom{ 0, blocklist.size() };I don't understand when the following triggers:          if (board.getDim(i, j + block.size()) > 1)        {            gameOver = true;It's probably in the code somewhere, but I don't feel like tracking it down now.  A comment of why we are comparing to 1 would be helpful.  