Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

I need a peer review of my code here. I take all comments given seriously, so pl

ID: 3847571 • Letter: I

Question

I need a peer review of my code here. I take all comments given seriously, so please make them known.

#include <iostream>
#include <vector>
#include <algorithm>
#include <random>

#ifdef __linux__
/*****************************************************************************
Martin Metzen   
Crerated 6-5-2017
****************************************************************************/
#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() ");
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 << "[" << y << ";" << x << "H";
}

void clearScreen(bool moveToStart = true) {
std::cout << "";
if (moveToStart)
gotoxy(1, 1);
}
inline
void print(const std::string& str, COORD& coord)
{
gotoxy(coord.X, coord.Y);
std::cout << str << std::flush;
}
inline
void print(const char* str, COORD& coord){
gotoxy(coord.X, coord.Y);
std::cout << str << std::flush;
}
inline
void print(char 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>
static HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
static CONSOLE_SCREEN_BUFFER_INFO csbi;
void clearScreen()
{
DWORD count;
DWORD cellCount;
COORD homeCoords = { 0, 0 };

if (!GetConsoleScreenBufferInfo(hStdOut, &csbi))
std::cerr << "ERROR GetConsoleScreenBufferInfo - clearScreen : "
<< GetLastError() << std::endl;

cellCount = csbi.dwSize.X *csbi.dwSize.Y;

FillConsoleOutputCharacter( hStdOut, (TCHAR) ' ',cellCount, homeCoords, &count);

FillConsoleOutputAttribute( hStdOut, csbi.wAttributes, cellCount, homeCoords, &count);

SetConsoleCursorPosition(hStdOut, homeCoords);
}
void gotoxy(int x, int y)
{
COORD coord;
coord.X = x;
coord.Y = y;
SetConsoleCursorPosition(hStdOut, coord);
}

static DWORD cCharsWritten;

inline
void print(const std::string& str, COORD& coord)
{
WriteConsoleOutputCharacter(hStdOut, str.c_str(), str.length(), coord, &cCharsWritten);
}
inline
void print(const TCHAR* str, COORD& coord)
{
WriteConsoleOutputCharacter(hStdOut, str, _tcslen(str), coord, &cCharsWritten);
}
inline
void print(TCHAR c, COORD& coord, bool dummy = true)
{
FillConsoleOutputCharacter(hStdOut, c, 1, coord, &cCharsWritten);
}
#else
#error "OS not supported!"
#End If

using Matrix = std::vector<std::vector<int>>;

constexpr std::initializer_list<size_t> il =
{
0, 1, 2, 3
};

constexpr std::initializer_list<size_t> ilBoard =
{
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20
};

constexpr std::initializer_list<size_t> ilBoardRow =
{
0,1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
};

static std::vector<Matrix> blockList =
{
{
{ 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 }
}
};

Class NonCopyable
{
public:
NonCopyable() = default;
private:
NonCopyable(const NonCopyable &) = delete;
NonCopyable(const NonCopyable &&) = delete;
NonCopyable& operator = (const NonCopyable&) = delete;
};


Class Random : Private NonCopyable
{
public:
Random(int min, int max)
: mUniformDistribution(min, max)
{}

int operator()()
{
return mUniformDistribution(mEngine);
}
private:
std::default_random_engine mEngine{ std::random_device()() };
std::uniform_int_distribution<int> mUniformDistribution;
};

Class Tetris : Private NonCopyable
{
public:
Tetris()
{
mBlock.resize(il.size(), std::vector<int>(il.size(), 0));
mBoard.resize(ilBoard.size(), std::vector<int>(ilBoardRow.size(), 0));
mStage.resize(ilBoard.size(), std::vector<int>(ilBoardRow.size(), 0));
};

private:
bool makeBlocks();
void moveBlock(int, int);
bool isCollide(int, int);
bool rotateBlock();
void isFull();
void checkLine();

virtual void display(){};
virtual void GameOverScreen() {};

Random getRandom{ 0, (blockList.size() - 1) };
Matrix mStage;
Matrix mBlock;

int y = 0;
int x = il.size();

protected:
void initField();
void spawnBlock();
void userInput();

bool gameOver = false;
Matrix mBoard;
};

void Tetris::initField()
{
for (auto i = ilBoard.begin(); i != ilBoard.end() - 1; ++i)
{
for (auto j = ilBoardRow.begin(); j != ilBoardRow.end() - 1; ++j)
{
if ((*j == 0) || (*j == ilBoardRow.size() - 2) || (*i == ilBoard.size() - 2))
{
mBoard[*i][*j] = mStage[*i][*j] = 9;
}
else
{
mBoard[*i][*j] = mStage[*i][*j] = 0;
}
}
}

makeBlocks();

display();
}

bool Tetris::makeBlocks()
{
x = il.size();
y = 0;

int blockType = getRandom();

for (auto i : il)
{
for (auto j : il)
{
mBlock[i][j] = blockList[blockType][i][j];
}
}

for (auto i : il)
{
for (auto j : il)
{
mBoard[i][j + il.size()] = mStage[i][j + il.size()] + mBlock[i][j];
}
}
return false;
}


void Tetris::isFull()
{
for (auto i : il)
{
for (auto j : il)
{   
if(mBoard[i][j + il.size()] > 1)
{
gameOver = true;
}
}
}
}

void Tetris::moveBlock(int x2, int y2)
{

//Remove block
for (auto i : il)
{
for (auto j : il)
{
mBoard[y + i][x + j] -= mBlock[i][j];
}
}

//Update coordinates
x = x2;
y = y2;

// assign a block with the updated value
for (auto i : il)
{
for (auto j : il)
{
mBoard[y + i][x + j] += mBlock[i][j];
}
}

display();
}

void Tetris::checkLine()
{
std::copy(mBoard.begin(), mBoard.end(), mStage.begin());

for (auto i = ilBoard.begin() + 1; i != ilBoard.end() - 2; ++i)
{
bool isCompeteLine = true;

for (auto j = ilBoardRow.begin() + 1; j != ilBoardRow.end() - 1; ++j)
{
if (mStage[*i][*j] == 0)
{
isCompeteLine = false;
}
}

if (isCompeteLine)
{
for (auto j : il)
std::copy(mStage[*i - 1 - j].begin(), mStage[*i - 1 - j].end(), mStage[*i - j].begin());
}
}

std::copy(mStage.begin(), mStage.end(), mBoard.begin());
}

bool Tetris::isCollide(int x2, int y2)
{
for (auto i : il)
{
for (auto j : il)
{
if (mBlock[i][j] && mStage[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()
{
Matrix temp(il.size(), std::vector<int>(il.size(), 0));

std::copy(mBlock.begin(), mBlock.end(), temp.begin());

// Rotate
for (auto i : il)
{
for (auto j : il)
{
if (i < j)
{
std::swap(mBlock[i][j], mBlock[j][i]);
}
}

std::reverse(mBlock[i].begin(), mBlock[i].end());
}

if (isCollide(x, y))
{ // And stop if it overlaps not be rotated
std::copy(temp.begin(), temp.end(), mBlock.begin());
return true;
}

for (auto i : il)
{
for (auto j : il)
{
mBoard[y + i][x + j] -= temp[i][j];
mBoard[y + i][x + j] += mBlock[i][j];
}
}

display();

return false;
}

void Tetris::spawnBlock()
{
if (!isCollide(x, y + 1))
{
moveBlock(x, y + 1);
}
else
{
checkLine();
makeBlocks();
isFull();
display();
}
}

Class Game : Public Tetris
{
public:
Game() = default;
int menu();
void gameLoop();
private:
void introScreen();

virtual void display();
virtual void gameOverScreen();

size_t GAMESPEED = 20000;
};

void Game::gameOverScreen()
{
COORD coord = { 0, 0 };
coord.Y += 2;
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);

gotoxy((coord.X = strlen("Press any key and enter") + 1), coord.Y++);

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 += 2;
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 += 5;

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 (auto i : ilBoard)
{
for (auto j : ilBoardRow)
{
switch (mBoard[i][j])
{
case 0:
std::cout << ' ';
break;
case 9:
std::cout << '@';
break;
default:
std::cout << '#';
break;
}
}
std::cout << std::endl;
}

COORD coord = { 0, ilBoard.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;
default:
COORD coord = { 0, 0 };
print("Choose 1~2", coord);
return -1;
}
return 0;
}

Explanation / Answer

The review comments are given in the bold letters against the statements. Have a look.

#include <iostream>
#include <vector>
#include <algorithm>
#include <random>

#ifdef __linux__ //Do we need to have check for solaris operating system too.
/*****************************************************************************
Martin Metzen
Crerated 6-5-2017
****************************************************************************/
#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() ");
        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 << "[" << y << ";" << x << "H"; // we should right "using namespace std;" in the begining of the code
}

void clearScreen(bool moveToStart = true) {
    std::cout << "";
    if (moveToStart)
        gotoxy(1, 1);
}
inline
void print(const std::string& str, COORD& coord)
{
    gotoxy(coord.X, coord.Y);
    std::cout << str << std::flush;
}
inline
void print(const char* str, COORD& coord){
    gotoxy(coord.X, coord.Y);
    std::cout << str << std::flush;
}
inline
void print(char 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>
static HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
static CONSOLE_SCREEN_BUFFER_INFO csbi;
void clearScreen()
{
    DWORD                      count;
    DWORD                      cellCount;
    COORD                      homeCoords = { 0, 0 };

    if (!GetConsoleScreenBufferInfo(hStdOut, &csbi))
        std::cerr << "ERROR GetConsoleScreenBufferInfo - clearScreen : "
                  << GetLastError() << std::endl;

    cellCount = csbi.dwSize.X *csbi.dwSize.Y;

    FillConsoleOutputCharacter( hStdOut, (TCHAR) ' ',cellCount, homeCoords, &count);

    FillConsoleOutputAttribute( hStdOut, csbi.wAttributes, cellCount, homeCoords, &count);

    SetConsoleCursorPosition(hStdOut, homeCoords);
}
void gotoxy(int x, int y)
{
    COORD coord;
    coord.X = x;
    coord.Y = y;
    SetConsoleCursorPosition(hStdOut, coord);
}

static DWORD cCharsWritten;

inline
void print(const std::string& str, COORD& coord)
{
    WriteConsoleOutputCharacter(hStdOut, str.c_str(), str.length(), coord, &cCharsWritten);
}
inline
void print(const TCHAR* str, COORD& coord)
{
    WriteConsoleOutputCharacter(hStdOut, str, _tcslen(str), coord, &cCharsWritten);
}
inline
void print(TCHAR c, COORD& coord, bool dummy = true)
{
    FillConsoleOutputCharacter(hStdOut, c, 1, coord, &cCharsWritten);
}
#else
#error "OS not supported!"
#End If

using Matrix = std::vector<std::vector<int>>;

constexpr std::initializer_list<size_t> il =
{
    0, 1, 2, 3
};

constexpr std::initializer_list<size_t> ilBoard =
{
    0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20
};

constexpr std::initializer_list<size_t> ilBoardRow =
{
    0,1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
};

static std::vector<Matrix> blockList =
{
    {
        { 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 }
    }
};

Class NonCopyable
{
public:
    NonCopyable() = default;
private:
    NonCopyable(const NonCopyable &) = delete;
    NonCopyable(const NonCopyable &&) = delete;
    NonCopyable& operator = (const NonCopyable&) = delete;
};


    Class Random : Private NonCopyable
{
public:
    Random(int min, int max)
        : mUniformDistribution(min, max)
    {}

    int operator()()
    {
        return mUniformDistribution(mEngine);
    }
private:
    std::default_random_engine mEngine{ std::random_device()() };
    std::uniform_int_distribution<int> mUniformDistribution;
};

        Class Tetris : Private NonCopyable
{
public:
    Tetris()
    {
        mBlock.resize(il.size(), std::vector<int>(il.size(), 0));
        mBoard.resize(ilBoard.size(), std::vector<int>(ilBoardRow.size(), 0));
        mStage.resize(ilBoard.size(), std::vector<int>(ilBoardRow.size(), 0));
    };

private:
    bool makeBlocks();
    void moveBlock(int, int);
    bool isCollide(int, int);
    bool rotateBlock();
    void isFull();
    void checkLine();

    virtual void display(){};
    virtual void GameOverScreen() {};
   //Tetris Class should have virtual destructor
    Random getRandom{ 0, (blockList.size() - 1) };
    Matrix mStage;
    Matrix mBlock;

    int y = 0;
    int x = il.size();

protected:
    void initField();
    void spawnBlock();
    void userInput();

    bool gameOver = false;
    Matrix mBoard;
};

void Tetris::initField()
{
    for (auto i = ilBoard.begin(); i != ilBoard.end() - 1; ++i)
    {
        for (auto j = ilBoardRow.begin(); j != ilBoardRow.end() - 1; ++j)
        {
            if ((*j == 0) || (*j == ilBoardRow.size() - 2) || (*i == ilBoard.size() - 2))
            {
                mBoard[*i][*j] = mStage[*i][*j] = 9;
            }
            else
            {
                mBoard[*i][*j] = mStage[*i][*j] = 0;
            }
        }
    }

    makeBlocks();

    display();
}

bool Tetris::makeBlocks()
{
    x = il.size();
    y = 0;

    int blockType = getRandom();

    for (auto i : il)
    {
        for (auto j : il)
        {
            mBlock[i][j] = blockList[blockType][i][j];
        }
    }

    for (auto i : il)
    {
        for (auto j : il)
        {
            mBoard[i][j + il.size()] = mStage[i][j + il.size()] + mBlock[i][j];
        }
    }
    return false;
}


void Tetris::isFull()
{
    for (auto i : il)
    {
        for (auto j : il)
        {     
            if(mBoard[i][j + il.size()] > 1)
            {
                gameOver = true;
            }
        }
    }
}

void Tetris::moveBlock(int x2, int y2)
{

    //Remove block
    for (auto i : il)
    {
        for (auto j : il)
        {
            mBoard[y + i][x + j] -= mBlock[i][j];
        }
    }

    //Update coordinates
    x = x2;
    y = y2;

    // assign a block with the updated value
    for (auto i : il)
    {
        for (auto j : il)
        {
            mBoard[y + i][x + j] += mBlock[i][j];
        }
    }

    display();
}

void Tetris::checkLine()
{
    std::copy(mBoard.begin(), mBoard.end(), mStage.begin());

    for (auto i = ilBoard.begin() + 1; i != ilBoard.end() - 2; ++i)
    {
        bool isCompeteLine = true;

        for (auto j = ilBoardRow.begin() + 1; j != ilBoardRow.end() - 1; ++j)
        {
            if (mStage[*i][*j] == 0)
            {
                isCompeteLine = false;
            }
        }

        if (isCompeteLine)
        {
            for (auto j : il)
                std::copy(mStage[*i - 1 - j].begin(), mStage[*i - 1 - j].end(), mStage[*i - j].begin());
        }
    }

    std::copy(mStage.begin(), mStage.end(), mBoard.begin());
}

bool Tetris::isCollide(int x2, int y2)
{
    for (auto i : il)
    {
        for (auto j : il)
        {
            if (mBlock[i][j] && mStage[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()
{
    Matrix temp(il.size(), std::vector<int>(il.size(), 0));

    std::copy(mBlock.begin(), mBlock.end(), temp.begin());

    // Rotate
    for (auto i : il)
    {
        for (auto j : il)
        {
            if (i < j)
            {
                std::swap(mBlock[i][j], mBlock[j][i]);
            }
        }

        std::reverse(mBlock[i].begin(), mBlock[i].end());
    }

    if (isCollide(x, y))
    { // And stop if it overlaps not be rotated
        std::copy(temp.begin(), temp.end(), mBlock.begin());
        return true;
    }

    for (auto i : il)
    {
        for (auto j : il)
        {
            mBoard[y + i][x + j] -= temp[i][j];
            mBoard[y + i][x + j] += mBlock[i][j];
        }
    }

    display();

    return false;
}

void Tetris::spawnBlock()
{
    if (!isCollide(x, y + 1))
    {
        moveBlock(x, y + 1);
    }
    else
    {
        checkLine();
        makeBlocks();
        isFull();
        display();
    }
}

            Class Game : Public Tetris
{
public:
    Game() = default;
    int menu();
    void gameLoop();
private:
    void introScreen();

    virtual void display();
    virtual void ();

    size_t GAMESPEED = 20000; //This is constant, so should be decleared outside the class
};

void Game::gameOverScreen()
{
    COORD coord = { 0, 0 };
    coord.Y += 2;
    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);

    gotoxy((coord.X = strlen("Press any key and enter") + 1), coord.Y++);

    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 += 2;
    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 += 5;

    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 (auto i : ilBoard)
    {
        for (auto j : ilBoardRow)
        {
            switch (mBoard[i][j])
            {
                case 0:
                    std::cout << ' ';
                    break;
                case 9:
                    std::cout << '@';
                    break;
                default:
                    std::cout << '#';
                    break;
            }
        }
        std::cout << std::endl;
    }

    COORD coord = { 0, ilBoard.size() };

    print("     A: left     S: down     D: right            Rotation[Space]", coord);

    if (gameOver)
    {
        clearScreen();
        gameOverScreen();
    }
}

int main()
{
    Game game;
    switch (game.menu()) //Not a correct way to do so, according to coding guidelines.
    {
        case 1:
            game.gameLoop();
            break;
        case 2:
            return 0;
        default:
            COORD coord = { 0, 0 };
            print("Choose 1~2", coord); //Format specifier is not mentioned in the print statement
            return -1;
    }
    return 0;
}

Hire Me For All Your Tutoring Needs
Integrity-first tutoring: clear explanations, guidance, and feedback.
Drop an Email at
drjack9650@gmail.com
Chat Now And Get Quote