linux environment C++ to achieve Tetris
- 2020-06-07 04:52:17
- OfStack
Example of this article for you to share C++ to achieve the specific code of Tetris, for your reference, the specific content is as follows
The running environment of this program is linux, using multithreading. A thread was created for drawing and a thread for getting keys. There are 1 areas in the program that need to be improved, such as the global variables defined in lines 336-338 and the objects declared. The declared Block and Table objects should be inside the main function and then passed as arguments to the thread function getkey. But it seems that only one object argument can be passed to the thread function. Hope the master can improve the program.
ps: Since multithreading is used, and pthread is not the default library for linux, you need to specify the thread library at compile time. g++ -o ES16en-ES17en block.cpp
#include <iostream>
#include <cstdlib>
#include <pthread.h>
#include <time.h>
#include<termios.h>
#include<fcntl.h>
#define TABLE_SIZE 20
#define BLOCK_SIZE 4
#define SLEEP_TIME 500
using namespace std;
struct grid{int x; int y;}; // coordinates
/////////////////////Block class //////////////////////
class Block
{
public:
enum direct{UP, DOWN, LEFT, RIGHT}; // Define the direction
grid g[BLOCK_SIZE]; // The coordinates of the square
void def_block(grid g1, grid g2, grid g3, grid g4); // The definition of square
void rotate(); // gururin
void move(int dir); // Mobile square
void set_cen(grid g); // Set the center of the square rotation
grid get_cen(); // Gets the center of the square rotation
void set_type(int t); // Set the square type
int get_type(); // Get the block type
void back(); // Rotating reduction
void creat_block(int x, int y); // Randomly generated block
private:
grid center; // Center of square rotation
int type; // Square type
};
void Block::def_block(grid g1, grid g2, grid g3, grid g4) {
g[0]=g1; g[1]=g2; g[2]=g3; g[3]=g4;
}
void Block::rotate() {
int x, y, i=0;
for(i; i<=3; i++) {
x=g[i].x-center.x; y=g[i].y-center.y;
g[i].x=center.x+y; g[i].y=center.y-x;
}
}
void Block::move(int dir) {
int d=dir, i=0;
switch(d) {
case UP: {
for(i; i<=3; i++) g[i].y++;
center.y++; break;
}
case DOWN: {
for(i; i<=3; i++) g[i].y--;
center.y--; break;
}
case LEFT: {
for(i; i<=3; i++) g[i].x--;
center.x--; break;
}
case RIGHT: {
for(i; i<=3; i++) g[i].x++;
center.x++; break;
}
}
}
void Block::set_cen(grid g) {
center=g;
}
grid Block::get_cen() {
return center;
}
void Block::set_type(int t) {
type=t;
}
int Block::get_type() {
return type;
}
void Block::back() {
int x, y, i=0;
for(i; i<=3; i++) {
x=g[i].x-center.x; y=g[i].y-center.y;
g[i].x=center.x-y; g[i].y=center.y+x;
}
}
void Block::creat_block(int x, int y) { // Randomly create squares
int ran;
grid g[BLOCK_SIZE];
ran=1+rand()%7;
switch(ran) {
//L
case 1: {
g[0].x=x/2; g[0].y=y-3;
g[1].x=g[0].x; g[1].y=g[0].y+1;
g[2].x=g[0].x; g[2].y=g[0].y+2;
g[3].x=g[0].x+1; g[3].y=g[0].y;
set_cen(g[0]); set_type(1); break;
}
// the L
case 2: {
g[0].x=x/2; g[0].y=y-3;
g[1].x=g[0].x; g[1].y=g[0].y+1;
g[2].x=g[0].x; g[2].y=g[0].y+2;
g[3].x=g[0].x-1; g[3].y=g[0].y;
set_cen(g[0]); set_type(2); break;
}
//Z
case 3: {
g[0].x=x/2; g[0].y=y-2;
g[1].x=g[0].x; g[1].y=g[0].y+1;
g[2].x=g[0].x+1; g[2].y=g[0].y+1;
g[3].x=g[0].x-1; g[3].y=g[0].y;
set_cen(g[0]); set_type(3); break;
}
// the Z
case 4: {
g[0].x=x/2; g[0].y=y-2;
g[1].x=g[0].x; g[1].y=g[0].y+1;
g[2].x=g[0].x+1; g[2].y=g[0].y+1;
g[3].x=g[0].x-1; g[3].y=g[0].y;
set_cen(g[0]); set_type(4); break;
}
// tian
case 5: {
g[0].x=x/2; g[0].y=y-2;
g[1].x=g[0].x; g[1].y=g[0].y+1;
g[2].x=g[0].x+1; g[2].y=g[0].y+1;
g[3].x=g[0].x+1; g[3].y=g[0].y;
set_cen(g[0]); set_type(5); break;
}
//1
case 6: {
g[0].x=x/2; g[0].y=y-3;
g[1].x=g[0].x; g[1].y=g[0].y+1;
g[2].x=g[0].x; g[2].y=g[0].y+2;
g[3].x=g[0].x; g[3].y=g[0].y-1;
set_cen(g[0]); set_type(6); break;
}
// mountain
case 7: {
g[0].x=x/2; g[0].y=y-2;
g[1].x=g[0].x; g[1].y=g[0].y+1;
g[2].x=g[0].x-1; g[2].y=g[0].y;
g[3].x=g[0].x+1; g[3].y=g[0].y;
set_cen(g[0]); set_type(7); break;
}
default: ;
}
def_block(g[0], g[1], g[2], g[3]);
}
/////////////////////////////////////////
////////////////////Table class //////////////////////
class Table
{
public:
Table() { // To construct a board
height=20; width=10; count=0;
init_table();
}
Table(int x, int y);
int set_block(Block bl); // Put a square
void clr_block(Block bl); // Remove squares
int clr_line(int y); // Line elimination
int get_h(); // Get the checkerboard height
int get_w(); // Get the checkerboard width
int if_full(int y); // Determines whether the row is full
int get_table(int x, int y); // Gets points on the checkerboard
void paint(); // Drawing board
void move_line(int y); // The entire line down
void set_count(int c); // Record the score
int get_count(); // Get score
private:
int table[TABLE_SIZE][TABLE_SIZE];// The board
int height, width; // The height and width of the board
int count; // score
void init_table(); // Checkerboard initialization
};
void Table::init_table() {
int i=0, j=0;
for(i; i<width; i++) {
for(j=0; j<height; j++) {
table[i][j]=0;
}
}
}
Table::Table(int x, int y) {
height=y; width=x; count=0;
init_table();
}
int Table::set_block(Block bl) {
int x, y;
int i;
for(i=0; i<=3; i++) {
x=bl.g[i].x; y=bl.g[i].y;
if(table[x][y]!=0 || x>=width || x<0 || y>=height || y<0) {
return 0;
}
}
for(i=0; i<=3; i++) {
x=bl.g[i].x; y=bl.g[i].y;
table[x][y]=1;
}
return 1;
}
void Table::clr_block(Block bl) {
int x, y;
for(int i=0; i<=3; i++) {
x=bl.g[i].x; y=bl.g[i].y;
table[x][y]=0;
}
}
int Table::clr_line(int y) {
if(y<0 || y>=height) return 0;
for(int i=0; i<width; i++) {
table[i][y]=0;
}
return 1;
}
int Table::get_h() {
return height;
}
int Table::get_w() {
return width;
}
int Table::if_full(int y) {
int i=0;
for(i; i<width; i++) {
if(table[i][y]==0) return 0;
}
return 1;
}
int Table::get_table(int x, int y) {
return table[x][y];
}
void Table::paint() {
int i, j;
for(i=0; i<width+2; i++) cout<<"-"<<flush;
cout<<"\n"<<flush;
for(i=height-1; i>=0; i--) {
cout<<"|"<<flush;
for(j=0; j<width; j++) {
if(table[j][i]==0) cout<<" "<<flush;
else cout<<"▣"<<flush;
}
if(i==10)
cout<<"| Score: "<<get_count()<<endl;
else if(i==7)
cout<<"| Press 'q' to quit!"<<endl;
else
cout<<"|"<<endl;
}
for(i=0; i<width+2; i++) cout<<"-"<<flush;
cout<<"\n"<<flush;
//cout<<" Score: "<<get_count()<<endl;
}
void Table::move_line(int y) {
int i, j;
for(i=y; i<height-1; i++) {
for(j=0; j<width; j++) {
table[j][i]=table[j][i+1];
}
}
}
void Table::set_count(int c) {
count+=c;
}
int Table::get_count() {
return count;
}
///////////////////////////////////////////////////////
class Mythread
{
public:
void init();
static void *getkey(void *arg);// Thread functions must be defined in a class static Type to remove the class pointer.
static void *paint_loop(void *arg);
};
void Mythread::init()
{
pthread_t ntid,ntid2;
int err,err2;
err = pthread_create(&ntid,NULL,getkey,NULL);
err2 = pthread_create(&ntid2,NULL,paint_loop,NULL);
if(err != 0 || err2 != 0){
cout<<"can't create thread!"<<endl;
exit(0);
}
}
unsigned char flag=1,buf[2];// The global variable
Table tab(15, 20); // structure 1 a 15,20 The board of
Block bl; // structure 1 A falling square
void* Mythread::paint_loop(void *arg)
{
while(1)
{
system("clear");
tab.paint();
usleep(50000); // suspended 50 MS
}
}
void* Mythread::getkey(void *arg)
{
struct termios saveterm,nt;
fd_set rfds,rs;
struct timeval tv;
int i=0,q,r,fd=0;
tcgetattr(fd,&saveterm);
nt=saveterm;
nt.c_lflag &= ~ECHO;
nt.c_lflag &= ~ISIG;
nt.c_lflag &= ~ICANON;
tcsetattr(fd,TCSANOW,&nt);
FD_ZERO(&rs);
FD_SET(fd,&rs);
tv.tv_sec=0;
tv.tv_usec=0;
while(1)
{
read(0,buf,1);
r=select(fd+1,&rfds,NULL,NULL,&tv);
if(r<0)
{
write(1,"select() error.\n",16);
}
rfds=rs;
if(flag==2||buf[0]==113)// The game ends or the user presses 'q' Key, the program exit
{
tcsetattr(0,TCSANOW,&saveterm);
exit(0);
}
if(buf[0]<=68&&buf[0]>=65) flag=0;// If the key pressed is an arrow key, the position is marked 0 And the corresponding processing is performed .
if(flag==0)
{
if(buf[0]==65) {
//if(dir!=0) {
if(bl.get_type()==5) continue; // If the field shape appears, it will not be rotated
tab.clr_block(bl); // Clear the square 1 Time position
bl.rotate(); // Begin to spin
if(!tab.set_block(bl)) { // Write the rotated squares on the board
bl.back(); // If you fail to write ( For example, it's on the edge, or it's stuck ) Then the position before rotation is restored
continue;
tab.set_block(bl);
}
}
// Down (accelerated fall)
//dir=GetAsyncKeyState(VK_DOWN); // To get down
if(buf[0]==66) {
tab.clr_block(bl); // Clear the square 1 Time position
bl.move(bl.DOWN); // Move down the 1 step
if(!tab.set_block(bl)) { // Write the moved square on the board
bl.move(bl.UP); // If this fails, revert to the position before the move (that is, move up 1 Step)
tab.set_block(bl);
}
}
// Left (left shift)
//dir=GetAsyncKeyState(VK_LEFT);
if(buf[0]==68) {
tab.clr_block(bl);
bl.move(bl.LEFT);
if(!tab.set_block(bl)) {
bl.move(bl.RIGHT);
tab.set_block(bl);
}
}
// Right (right shift)
//dir=GetAsyncKeyState(VK_RIGHT);
if(buf[0]==67) {
tab.clr_block(bl);
bl.move(bl.RIGHT);
if(!tab.set_block(bl)) {
bl.move(bl.LEFT);
tab.set_block(bl);
}
}
flag=1;
}
}
tcsetattr(0,TCSANOW,&saveterm);
}
//////////// Main function part ///////////////////////
int main()
{
//Table tab(15, 20); // structure 1 a 15,20 The board of
//Block bl; // structure 1 A falling square
Mythread thread;
thread.init();
int dir,i,c;
while(true) {
// Generate square
srand(time(0));
bl.creat_block(tab.get_w(), tab.get_h());
// Decide if the game is over
if( !tab.set_block(bl) ) {
system("clear");
cout<<"GAME OVER!"<<endl;
flag=2;
cout<<"PRESS ANY KEY TO CONTINUE!"<<endl;
while(1);
}
/////////// Action button decision
while(true){
usleep(500000); // suspended 500 MS
///////////// Move down the 1 "
tab.clr_block(bl); // On the empty 1 Subsquare position
bl.move(bl.DOWN); // Move down the 1 step
if(!tab.set_block(bl)) { // Whether the bottom of the
bl.move(bl.UP); // If it hits bottom, restore the position before it hit bottom
tab.set_block(bl);
break;
}
}
// If the line is full, the line goes away
for(i=0; i<tab.get_h(); i++) {
if(tab.if_full(i)) { // Whether the full line
tab.clr_line(i); // If yes, cancel the line
tab.move_line(i); // Move the checkerboard information above the eliminated lines down
i--; // As you move down, recheck this 1 Is the row full (there may be several lines that cancel at the same time)
tab.set_count(100); // Record the score
}
}
}
return 0;
}