Code:
#include <iostream.h>
#include <stdio.h>
#include <windows.h>
#include <conio.h>
// bad practice defines
#define ROWS 15
#define COLS 45
// game piece object
struct TPiece{
int block[3][3];
int color;
};
struct boardSpace {
int value;
int color;
};
// board management class
class CGame
{
public:
CGame();
~CGame();
void spawn(); // spawn current preview piece - and replace a new piece
void fall(); // moves block sideways 1 column in specified time
void move(int y, int x); // voluntary movement and rotations
void draw(); // draw the board - and active piece.
bool collision(int y, int x); // check for being in place
bool removeCol(); // check for completed columns and remove them
void fix(); // pushes down columns into new spaces created from completed columns
void set(); // sets active piece in place - calls spawn
bool checkLose(); // you suck..
TPiece * rotate(TPiece * piece);
TPiece * getActive() { return this->active; }
void setActive(TPiece * piece) { this->active = piece; }
private:
TPiece *active; // currently active game piece
TPiece *preview; // preview of coming game piece
int aX, aY; // location of the activePiece
int X, Y; // piece location according to the board
boardSpace board[ROWS][COLS];
long lastTime; // last time block was shoved
int speed; // how fast does block move
public:
bool paused; // game pauses
bool altered; // does screen need to be redrawn?
bool bPlaced; // is active place going to collide next move? If so -next move set its position but dont move it
};
TPiece rotatePiece();
TPiece * createPiece( int ncolor );
CGame *game;
char * quitMessage; // win/lose message
int score; // game score
long lastkey;
void createBox( TPiece * piece );
void createLong( TPiece * piece );
void createZig( TPiece * piece );
void createZag( TPiece * piece );
void createTee( TPiece * piece );
void drawPiece(TPiece * piece, int x, int y);
void gotoxy(int x, int y);
void drawBoard();
int main() {
// printf("This is a test.\n");
game = new CGame();
game->spawn();
game->draw();
getch();
game->paused = false;
// game loop
char Input=0;
char lastIn = 0;
while(Input!=27) //Loop while ESC is not pressed.
{
Input=0;
if(kbhit()) Input=getch(); //Store the pressed key (if a key is pressed)
if(Input == 27 ) {
quitMessage = "I can't believe your quiting at this pivotal moment!! - Your score was:";
break;
}
if( Input ) lastIn = Input;
long currentTime=timeGetTime();
if(currentTime - lastkey > 50)
{
gotoxy(0, 23);
//printf("you pressed %i\n", (int)Input);
if(lastIn == 'e')
game->move(-1,0);
else if(lastIn == 'd')
game->move(1,0);
if(lastIn== 'r')
game->setActive( game->rotate(game->getActive()) );
lastIn = 0;
lastkey = currentTime; //reset start time variable
}
//drawBoard();
game->fall();
if(game->altered)
game->draw();
// if youve let things pile too much you lose
if(game->checkLose()) {
Input=27; // same as esc:
quitMessage = "Game over - you lost. Your score was:";
}
gotoxy(0, 19); printf("Your score is: %i", score);
}
gotoxy(0, 20);
printf("%s %i\n Thanks for playing my dos tetris clone!",quitMessage, score);
return 0;
}
TPiece rotatePiece( TPiece * piece) {
TPiece result;
// rotate corners
result.block[0][0] = piece->block[2][0];
result.block[0][2] = piece->block[0][0];
result.block[2][2] = piece->block[0][2];
result.block[2][0] = piece->block[2][2];
// rotate middles
result.block[0][1] = piece->block[1][0];
result.block[1][2] = piece->block[0][1];
result.block[2][1] = piece->block[1][2];
result.block[1][0] = piece->block[2][1];
// center is the center
result.block[1][1] = piece->block[1][1];
// color
result.color = piece->color;
return result;
}
TPiece * createPiece( int ncolor ) {
TPiece *result = new TPiece;
for(int i = 0; i < 3; i ++ )
for( int j = 0; j < 3; j ++)
result->block[i][j] = 0;
result->color = ncolor;
return result;
}
void createBox( TPiece * piece ) {
for(int i = 0; i < 3; i++ )
for( int j = 0; j < 3; j++ )
piece->block[i][j] = 1;
}
void createLong( TPiece * piece ) {
for( int j = 0; j < 3; j++ )
piece->block[1][j] = 1;
}
void createZig( TPiece * piece ) {
piece->block[0][0] = 1; // _
piece->block[0][1] = 1;
piece->block[1][1] = 1; // |
piece->block[2][1] = 1; // -
piece->block[2][2] = 1;
}
void createZag( TPiece * piece ) {
piece->block[0][1] = 1; // _
piece->block[0][2] = 1;
piece->block[1][1] = 1; // |
piece->block[2][0] = 1; // -
piece->block[2][1] = 1;
}
void createTee( TPiece * piece ) {
piece->block[0][1] = 1;
piece->block[1][1] = 1;
piece->block[1][2] = 1;
piece->block[2][1] = 1;
}
void drawPiece( TPiece * piece, int y, int x) {
HANDLE hStdout;
hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
gotoxy( x, y );
for( int i = 0; i < 3; i++ ) {
for( int j = 0; j < 3; j++ ) {
if( piece->block[i][j] ) {
gotoxy( x + j, y+i );
SetConsoleTextAttribute(hStdout, piece->color); // blue bg, white text
printf("%c", char(219));
SetConsoleTextAttribute(hStdout, 121); // reset to grey.
} else {
//printf(" ");
}
}
}
}
void gotoxy(int x, int y) {
COORD pos;
pos.X = x;
pos.Y = y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),pos);
}
void drawBoard() {
// 201 205 187
// 205 188 219 186
// 219 219 186
// 205 187 219 186
// 200 205 188
gotoxy(0,0);
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 121);
// preview area
gotoxy(0,3+2);
printf("%c", char(201));
for( int i = 0; i < 7; i++ )
printf("%c", char(205));
printf("%c", char(187));
gotoxy(8, 6); printf("%c", char(200)); printf("%c", char(188));
gotoxy(0, 6); printf("%c", char(186));
gotoxy(0, 7); printf("%c", char(186));
gotoxy(0, 8); printf("%c", char(186));
gotoxy(0, 9); printf("%c", char(186));
gotoxy(0, 10); printf("%c", char(186));
gotoxy(8, 10); printf("%c", char(201)); printf("%c", char(187));
gotoxy(0, 11); printf("%c", char(200));
for( i = 0; i < 7; i++ )
printf("%c", char(205));
printf("%c", char(188));
gotoxy(9, 5); printf("%c", char(186));
gotoxy(9, 4); printf("%c", char(186));
gotoxy(9, 3); printf("%c", char(186));
gotoxy(9, 2); printf("%c", char(186));
gotoxy(9, 1); printf("%c", char(186));
gotoxy(9, 0); printf("%c", char(201));
gotoxy(9, 11); printf("%c", char(186));
gotoxy(9, 12); printf("%c", char(186));
gotoxy(9, 13); printf("%c", char(186));
gotoxy(9, 14); printf("%c", char(186));
gotoxy(9, 15); printf("%c", char(186));
gotoxy(9, 16); printf("%c", char(200));
gotoxy(10,0);
// playing area
for( i = 0; i < 49; i++ )
printf("%c", char(205));
printf("%c", char(187));
for( i = 0; i < 15; i++ ) {
gotoxy( 59, i+1 );
printf("%c", char(186));
}
gotoxy(10,16);
for( i = 0; i < 49; i++ )
printf("%c", char(205));
printf("%c", char(188));
// filling
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 121);
gotoxy(10, 1);
for( i = 0; i < 15; i++ ) {
for( int j = 0; j < 49; j++ ) {
gotoxy(10+j, i+1);
printf(" ");
}
}
gotoxy(1, 7);
for( i = 0; i < 5; i++ ) {
for( int j = 0; j < 7; j++ ) {
gotoxy(1+j, i+6);
printf(" ");
}
}
for( i = 0; i < 3; i++ ) {
for( int j = 0; j < 2; j++ ) {
gotoxy(8+j, i+7);
printf(" ");
}
}
}
CGame::CGame() {
this->aX = 0;
this->aY = 0;
this->X = 0;
this->Y = 6;
for( int i = 0; i < ROWS; i++ )
for( int j = 0; j < COLS; j++ ) {
this->board[i][j].value = 0; // empty board
this->board[i][j].color = 0; // doesnt really matter
}
this->paused = true;
this->altered = true;
this->active = NULL;
this->bPlaced = false;
this->speed = 150;
int random = rand()%5;
this->preview = createPiece( random );
switch( random )
{
case 1: // box
createBox(this->preview);
break;
case 2: // long
createLong(this->preview);
break;
case 3: // zig
createZig(this->preview);
break;
case 4: // zag
createZag(this->preview);
break;
case 5: // tee
createTee(this->preview);
default: // none
createBox(this->preview);
break;
}
};
CGame::~CGame() {
};
void CGame::draw() {
drawBoard();
for( int i = 0; i < ROWS; i++ ) {
for( int j = 0; j < COLS; j++ ) {
if( this->board[i][j].value ) {
gotoxy(14+j, i+1);
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), this->board[i][j].color);
printf("%c", char(219));
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 121);
}
}
}
// preview piece
drawPiece( this->preview, 7, 3 );
// active piece
drawPiece( this->active, aY, aX);
/*
for( i = 0; i < ROWS; i++ ) {
for( int j = 0; j < COLS; j++ ) {
gotoxy(14+j, i+1);
printf("%i", this->board[i][j].value);
}
}
/*/
this->altered = false;
};
void CGame::fall() {
long currentTime=timeGetTime();
if(currentTime - this->lastTime > this->speed)
{
score++; // 1 point every push
this->altered = true;
if( bPlaced ) {
set();
this->bPlaced = false;
} else {
if( collision( this->Y, this->X+1 ) ) {
this->bPlaced = true;
} else {
this->aX += 1;
this->X += 1;
}
//do stuff
}
this->lastTime = currentTime; //reset start time variable
}
if(removeCol())
fix();
};
void CGame::fix() {
// gotoxy(0, 22);
// printf("Entered fixed");
this->altered = true;
for( int i = 0; i < ROWS; i++ ) {
for( int j = COLS-1; j > 0; j-- ) {
if( !this->board[i][j].value && this->board[i][j-1].value ) {
this->board[i][j].value = this->board[i][j-1].value;
this->board[i][j-1].value = 0;
}
}
}
// gotoxy(0, 23);
// printf("Exited fixed");
};
void CGame::move(int y, int x) { // protects from top / bottome boundry
this->altered = true;
if( ((this->Y + y >= 0 && (this->Y+1) + y < ROWS-1) && this->Y != 0 ) && !collision(this->Y+y, this->X+x) ) {
this->Y +=y;
this->aY +=y;
}
if( ((this->X + x >= 0 && (this->X+2) + x < COLS) && this->X != 0 ) && !collision(this->Y+y, this->X+x) ) {
this->X +=x;
this->aX +=x;
}
};
void CGame::spawn() {
this->altered = true;
this->active = this->preview;
this->aX = 14;
this->aY = 7;
this->X = 0;
this->Y = 6;
int random = rand()%5;
this->preview = createPiece(random);
switch( random )
{
case 1: // box
createBox(this->preview);
break;
case 2: // long
createLong(this->preview);
break;
case 3: // zig
createZig(this->preview);
break;
case 4: // zag
createZag(this->preview);
break;
case 5: // tee
createTee(this->preview);
break;
default: // none
createBox(this->preview);
break;
}
// gotoxy(0, ROWS+5);
// printf("type: %i", random);
// drawPiece(this->preview, 0, ROWS+6);
bPlaced = false;
};
void CGame::set() {
this->altered = true;
// no error checking for proper placing - should be done in collision()
for( int i = 0; i < 3; i++ ) {
for( int j = 0; j < 3; j++ ) {
if( this->active->block[i][j] ) {
this->board[i+Y][j+X].value = 1;
this->board[i+Y][j+X].color = this->active->color;
}
}
}
spawn();
}
bool CGame::collision(int y, int x) { // true for hitting right boundry - or nestling into place
for( int i = 0; i < 3; i++ ) {
for( int j = 0; j < 3; j++ ) {
if( this->active->block[i][j] == 1 && this->board[y+i][x+j].value == 1 )
return true;
if( this->active->block[i][j] == 1 && this->X+j == COLS-1 )
return true;
}
}
return false;
};
bool CGame::removeCol() {
bool fixme = false;
bool cleared = false;
for(int j = 0; j < COLS; j++ ) {
cleared = true;
for( int i = 0; i < ROWS; i++ ) {
if( !this->board[i][j].value )
cleared = false;
}
if( cleared ) {
for( i = 0; i < ROWS; i++ )
this->board[i][j].value = 0; // clear out column
fixme = true;
}
}
if( fixme ) return true;
else return false;
};
bool CGame::checkLose() {
for(int i = 0; i < ROWS; i++ )
if(this->board[i][0].value)
return true;
return false;
};
TPiece * CGame::rotate(TPiece * piece) {
TPiece *result = createPiece(0);
// rotate corners
result->block[0][0] = piece->block[2][0];
result->block[0][2] = piece->block[0][0];
result->block[2][2] = piece->block[0][2];
result->block[2][0] = piece->block[2][2];
// rotate middles
result->block[0][1] = piece->block[1][0];
result->block[1][2] = piece->block[0][1];
result->block[2][1] = piece->block[1][2];
result->block[1][0] = piece->block[2][1];
// center is the center
result->block[1][1] = piece->block[1][1];
// color
result->color = piece->color;
return result;
};