自定义俄罗斯方块

  • 单臂大回旋(风车)式旋转
  • 支持自定义方块
  • 支持修改棋盘大小
  • 暴肝一晚,码风混乱,欢迎拍砖/fad
    ###还有些bug
    1判定问题:
    一直旋转可能产生原力(卡过下落时间)…减缓掉落
    2积分加速还没有严格测试,手太残了,没测出来

食用方式
编译生成.exe
同文件夹下放1.txt,并输入方块信息

4.23更新:下键加速下落
4.25更新:双缓存防闪屏
4.25更新1:修复结束不显示:Game over
参考资料:https://blog.csdn.net/oHanTanYanYing/article/details/72179593

#include <iostream>
#include <fstream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <ctime>
#include <cmath>
#include <windows.h>
#include <algorithm>
using namespace std;

#define Col  14   //1,2,3,4最小公倍数 列   +2框 
#define Row  20  //10层              行   +2

#define min_col 0
#define min_row 0
#define max_col Col-1
#define max_row Row-1

#define edge 3
 
#define Max_long 5    //长 
#define Max_width 5   //宽 
#define Max_score_len 10
struct Shape
{
	int shape[Max_width][Max_long];
	int ture_long;
	int ture_width;
	int xx;
	int yy;
	int xx1;                     //旋转定位点 
	int yy1;
	int fig;                    //1,2,3,4  分别从初始逆时针 
};
//0---
//---1
class Russia
{
	private:
		int score;
		int speed;            //系统毫秒%speed=0时下落一节, speed =2000 - 200*(score%3) ||1000  
		int map[Row][Col];   //0未占用,1已占用 2下落块  edge画边界 
		int sum_shapes;       //形状总数 
		HANDLE h[2];
	    COORD coord;
	    DWORD bytes;
    	CONSOLE_CURSOR_INFO cci;
    	int now_h;
    	char *version;
	public:
				Shape *list;
		Russia();
		~Russia();
		void play();          //开始游戏
		int work(Shape);          //回合运行  -1 game over
		void In_shapes(string); //输入形状 
		void display();        //展现棋盘 
		void check(int,int);          //检查并修理      
		void draw(Shape &,int);    //0清空,1填充 
		void draw2(Shape &,int);     //填充2 
		int judge(Shape &,int ,int ,int);  //新的中心位置,新的姿态 
		void new_display();
		void turn_char(char *);
}; 
Russia::Russia():version("修改信息:2020.4.25 by ssy9")
{
	
    CONSOLE_CURSOR_INFO cci = {1, 0};
    h[0] = CreateConsoleScreenBuffer(
        GENERIC_WRITE,//定义进程可以往缓冲区写数据
        FILE_SHARE_WRITE,//定义缓冲区可共享写权限
        NULL,
        CONSOLE_TEXTMODE_BUFFER,
        NULL
    );
    h[1] = CreateConsoleScreenBuffer(
        GENERIC_WRITE,//定义进程可以往缓冲区写数据
        FILE_SHARE_WRITE,//定义缓冲区可共享写权限
        NULL,
        CONSOLE_TEXTMODE_BUFFER,
        NULL
    );

    cci.bVisible = 0;
    cci.dwSize = 1;
    SetConsoleCursorInfo(h[0], &cci);
    SetConsoleCursorInfo(h[1], &cci);
	coord.Y = 0;
	coord.X = 0;
	bytes = 0;
	now_h = 0;
	        
	memset(map,0,sizeof(map));
	for(int i=0;i<Row;i++)
	{
		for(int j=0;j<Col;j++)
		{
			if(i==0||j==0||i==Row-1||j==Col-1)
			{
				map[i][j] = edge;
			}
		}
	}
	score = 0;
}

Russia::~Russia()
{
	free(list);
}
void Russia::In_shapes(string fn)
{
	fn +='\0';
	ifstream file;
	file.open(fn.c_str(),ios::in);
	
	file>>this->sum_shapes;
	
	list = (Shape *)malloc(sizeof(Shape)*sum_shapes);
	
	for(int i=0;i<sum_shapes;i++)
	{
		file>>(list[i].ture_long)>>(list[i].ture_width);
		for(int j=0;j<list[i].ture_width;j++)
		{
			for(int k=0;k<list[i].ture_long;k++)
			{
				file>>list[i].shape[j][k];
			}
		}
	}
	file.close();
}
void Russia::display()
{
	for(int i=0;i<Row;i++)
	{
		for(int j=0;j<Col;j++)
		{
			
			switch(map[i][j])
			{
				case 0:
					cout<<"  ";
					break;
				case 1:
				case 2: 
					cout<<"█";
					break;
				case edge:
					cout<<"※";
					break;
			}
			
			//cout<<map[i][j];
		}
		cout<<endl;
	}
	cout<<"-------------------------------------------"<<endl;
	cout<<"你的分数为:"<<score<<endl;
}

void Russia::turn_char(char *p)
{
	int len = 1,tem=1;
	while(this->score/tem!=0)
	{
		tem*=10;
		len++;
	}
	int top = 0;
	int tem_score = this->score;
	while(len--)
	{
		tem/=10;
		if(tem==0)
			tem=1;
		p[top++]='0'+tem_score/tem;
		tem_score%=tem;
	} 
}

void Russia::new_display()
{
	coord.X = 0;
	coord.Y = 0;
	for(int i=0;i<Row;i++)
	{
		char tem[(Col+5)*2];
		int tail = 0;
		memset(tem,0,sizeof(tem));
		for(int j=0;j<Col;j++)
		{
			switch(map[i][j])
			{
				case 0:
					strcat(&tem[tail],"  ");
					tail+=2;
					break;
				case 1:
				case 2: 
					strcat(&tem[tail],"█");
					tail+=2;
					break;
				case edge:
					strcat(&tem[tail],"※");
					tail+=2;
					break;
			}
			//cout<<map[i][j];
		}
		coord.Y=i;
		WriteConsoleOutputCharacterA(h[now_h],&tem[0],strlen(tem),coord,&bytes);
	}
	//system("cls");
	//system("mode con cols=30 lines=26");
	SetConsoleActiveScreenBuffer(h[now_h]);
	coord.Y++;
	WriteConsoleOutputCharacterA(h[now_h],"--------------------",20,coord,&bytes);
	coord.Y++;
	char name[Max_score_len+10] = "score:  ";
	turn_char(&name[7]);
	WriteConsoleOutputCharacterA(h[now_h],name,strlen(name),coord,&bytes);
	coord.Y+=3;
	WriteConsoleOutputCharacterA(h[now_h],version,strlen(version),coord,&bytes);
	Sleep(100);
	now_h=(now_h+1)%2;	
}

void Russia::play()
{
	while(1)
	{
		//计算速度
		speed = 1000 - 100*(score/2);
		if(speed<30)
			speed = 30;               //此处修改速度
			
		int rand_shape = rand()%sum_shapes;
		
		if(work(list[rand_shape])==-1)
		{
			coord.Y=1;
			coord.X=Col*2+3;
			WriteConsoleOutputCharacterA(h[(now_h+1)%2],"Game over",9,coord,&bytes);	
			//cout<<"score:"<<score<<endl;
			//cout<<"Game over"<<endl;
			system("pause");
			return;
		}
	}
}
void Russia::check(int top,int bottom)   //top<=bottom
{
	for(int i=top;i<=bottom;i++)
	{
		int jud = 1;
		for(int j=1;j<=Col-2;j++)
		{
			if(map[i][j]==0)
			{
				jud = 0; //不能清理 
			}
		}
		if(jud == 1)
		{
			score++;
			for(int j=i-1;j>=1;j--)
			{
				int jud1=0;                 //全0标记 
				for(int k=1;k<=Col-2;k++)
				{
					map[j+1][k] = map[j][k];
					jud1=(jud1|map[j+1][k]);
				}
				if(jud == 0)               //全是0 复制完毕 
				{
					break;
				}
			}
		}
	}
}
void Russia::draw(Shape &now_shape,int tar)
{
	switch(now_shape.fig)
	{
		case 1:
			for(int i=0;i<now_shape.ture_long;i++)
			{
				for(int j=0;j<now_shape.ture_width;j++)
				{
					if(map[now_shape.yy+j][now_shape.xx+i]!=1)
					map[now_shape.yy+j][now_shape.xx+i] = ((now_shape.shape[j][i]&tar));
				}
			}
			break;
		case 2:
			for(int i=0;i<now_shape.ture_long;i++)
			{
				for(int j=0;j<now_shape.ture_width;j++)
				{
					if(map[now_shape.yy-i][now_shape.xx+j]!=1)
					map[now_shape.yy-i][now_shape.xx+j] = ((now_shape.shape[j][i]&tar));
				}
			}
			break;
		case 3:
			for(int i=0;i<now_shape.ture_long;i++)
			{
				for(int j=0;j<now_shape.ture_width;j++)
				{
					if(map[now_shape.yy-j][now_shape.xx-i]!=1)
					map[now_shape.yy-j][now_shape.xx-i] = ((now_shape.shape[j][i]&tar));   //
				}
			}	
			break;
		case 4:
			for(int i=0;i<now_shape.ture_long;i++)
			{
				for(int j=0;j<now_shape.ture_width;j++)
				{
					if(map[now_shape.yy+i][now_shape.xx-j]!=1)
					map[now_shape.yy+i][now_shape.xx-j] = ((now_shape.shape[j][i]&tar));
				}
			}	
			break;	
		}
}
void Russia::draw2(Shape &now_shape,int tar)
{
	switch(now_shape.fig)
	{
		case 1:
			for(int i=0;i<now_shape.ture_long;i++)
			{
				for(int j=0;j<now_shape.ture_width;j++)
				{
					if(tar==0)
					{
						if(map[now_shape.yy+j][now_shape.xx+i]==2)
							map[now_shape.yy+j][now_shape.xx+i]=0;
					}
					if(tar==1)
					{
						if(map[now_shape.yy+j][now_shape.xx+i]==0)
						map[now_shape.yy+j][now_shape.xx+i] = ((now_shape.shape[j][i]&tar)<<1);
					}
				}
			}
			break;
		case 2:
			for(int i=0;i<now_shape.ture_long;i++)
			{
				for(int j=0;j<now_shape.ture_width;j++)
				{
					if(tar==1)
						if(map[now_shape.yy-i][now_shape.xx+j]==0)
							map[now_shape.yy-i][now_shape.xx+j] = ((now_shape.shape[j][i]&tar)<<1);
					if(tar==0)
						if(map[now_shape.yy-i][now_shape.xx+j]==2)
							map[now_shape.yy-i][now_shape.xx+j]=0;
				}
			}
			break;
		case 3:
			for(int i=0;i<now_shape.ture_long;i++)
			{
				for(int j=0;j<now_shape.ture_width;j++)
				{
					if(tar==1)
						if(map[now_shape.yy-j][now_shape.xx-i]==0)
							map[now_shape.yy-j][now_shape.xx-i] = ((now_shape.shape[j][i]&tar)<<1);   //
					if(tar==0)
						if(map[now_shape.yy-j][now_shape.xx-i]==2)
							map[now_shape.yy-j][now_shape.xx-i]=0;
				}
			}	
			break;
		case 4:
			for(int i=0;i<now_shape.ture_long;i++)
			{
				for(int j=0;j<now_shape.ture_width;j++)
				{
					if(tar==1)
						if(map[now_shape.yy+i][now_shape.xx-j]==0)
							map[now_shape.yy+i][now_shape.xx-j] = ((now_shape.shape[j][i]&tar)<<1);
					if(tar==0)
						if(map[now_shape.yy+i][now_shape.xx-j]==2)
							map[now_shape.yy+i][now_shape.xx-j]=0;
				}
			}	
			break;	
		}
}
int Russia::judge(Shape &now_shape,int new_x,int new_y,int new_fig)
{
	switch(new_fig)
	{
		case 1:
			if(new_x<=0||new_x>=Col-1||new_y<=0||new_y>=Row-1)
				return 0;                                                               //是否越界 
			if((new_x+now_shape.ture_long-1>=max_col)||(new_y+now_shape.ture_width-1>=max_row))
				return 0;
			for(int i=0;i<now_shape.ture_long;i++)
			{
				for(int j=0;j<now_shape.ture_width;j++)
				{
					if(map[new_y+j][new_x+i]&now_shape.shape[j][i])     //是否重合 
						return 0;
				}
			}
			return 1;
			break;
		case 2:
			if(new_x<=0||new_x>=Col-1||new_y<=0||new_y>=Row-1)
				return 0;
			if((new_x+now_shape.ture_width-1>=max_col)||(new_y-now_shape.ture_long+1<=min_row))
				return 0;
			for(int i=0;i<now_shape.ture_long;i++)
			{
				for(int j=0;j<now_shape.ture_width;j++)
				{
					//cout<<(map[new_y-i][new_x+j]&now_shape.shape[j][i])<<endl;
					if((map[new_y-i][new_x+j]&now_shape.shape[j][i])==1)
						return 0;
				}
			}
			return 1;
			break;
		case 3:
			if(new_x<=0||new_x>=Col-1||new_y<=0||new_y>=Row-1)
				return 0;
			if((new_x-now_shape.ture_long+1<=min_col)||(new_y-now_shape.ture_width+1<=min_row))
				return 0;
			for(int i=0;i<now_shape.ture_long;i++)
			{
				for(int j=0;j<now_shape.ture_width;j++)
				{
					if(map[new_y-j][new_x-i]&now_shape.shape[j][i])   //
						return 0;
				}
			}	
			return 1;
			break;
		case 4:
			if(new_x<=0||new_x>=Col-1||new_y<=0||new_y>=Row-1)
				return 0;
			if((new_x-now_shape.ture_width+1<=min_col)||(new_y+now_shape.ture_long-1>=max_row))
				return 0;
			for(int i=0;i<now_shape.ture_long;i++)
			{
				for(int j=0;j<now_shape.ture_width;j++)
				{
					if(map[new_y+i][new_x-j]&now_shape.shape[j][i])
						return 0;
				}
			}	
			return 1;
			break;						
	}
}
int Russia::work(Shape now_shape)
{
	//初始化位置 
	now_shape.yy=1;
	now_shape.xx=1+rand()%(Col-2-now_shape.ture_long);
	now_shape.yy1=now_shape.ture_width;
	now_shape.xx1=now_shape.xx+now_shape.ture_long-1;
	now_shape.fig=1;
	//检查该位置是否重合
	for(int i=0;i<now_shape.ture_long;i++)
	{
		for(int j=0;j<now_shape.ture_width;j++)
		{
			if((map[j+now_shape.yy][i+now_shape.xx]&now_shape.shape[j][i])==1)  //重合不合法 
			{
				/*
				system("cls");
				cout<<"score:"<<score<<endl;
				cout<<"Game over"<<endl;
				system("pause");
				*/
				return -1;
			}
		}
	}
	while(clock()%speed!=0){}//基准时间 
	while(clock()%speed==0){}
	draw2(now_shape,1);
	//system("cls");
	new_display();
	//开始下落
	int drop_faster = 0;
	int last_clock=0;
	while(1)
	{
		if((clock()%speed<=50&&last_clock==1)||drop_faster==1)   //下落 
		{
			drop_faster = 0;
			//判断能不能落
			if(judge(now_shape,now_shape.xx,now_shape.yy+1,now_shape.fig)==1)//能落 
			{
				draw2(now_shape,0);     //清空
				now_shape.yy++;        //下降
				draw2(now_shape,1);      //填补
				//system("cls");
				new_display(); 
			}
			else
			{
				draw(now_shape,0);
				draw(now_shape,1);
				//system("cls");
				new_display(); 
				break;
			}
		}
		else                                   //显示并读取键盘状态 
		{
			if(clock()%speed!=0)
			{
				last_clock = 1;                 //更新flag 
			}
			int last_state = 0;
			if(GetKeyState(38)<0&&last_state==0)  //逆时针旋转 
			{
				last_state = 1;                   //更新状态 
				int ttem=now_shape.fig%4+1;
				if(judge(now_shape,now_shape.xx,now_shape.yy,ttem)==1)
				{
					draw2(now_shape,0);     //清空
					now_shape.fig=ttem;
					draw2(now_shape,1);      //填补
					//system("cls");
					new_display(); 					
				} 
			}
			if(GetKeyState(37)<0&&last_state==0)  //左
			{
				last_state = 1;                   //更新状态 
				if(judge(now_shape,now_shape.xx-1,now_shape.yy,now_shape.fig)==1)
				{
					draw2(now_shape,0);     //清空
					now_shape.xx--;
					draw2(now_shape,1);      //填补
					//system("cls");
					new_display(); 					
				} 
			}
			if(GetKeyState(39)<0&&last_state==0)  //右 
			{
				last_state = 1;                   //更新状态 
				if(judge(now_shape,now_shape.xx+1,now_shape.yy,now_shape.fig)==1)
				{
					draw2(now_shape,0);     //清空
					now_shape.xx++;
					draw2(now_shape,1);      //填补
					//system("cls");
					new_display(); 					
				} 
			}
			if(GetKeyState(40)<0&&last_state==0)
			{
				last_state=1;
				drop_faster = 1;
			}
		}
	} 
	
	check(min_row+1,max_row-1);
	return 1;
}

Russia russia;
int main()
{
	//system("mode con cols=30 lines=26");
	//SetConsoleTitle("俄罗斯方块 by ssy9"); 
	srand(time(0));
	russia.In_shapes("1.txt");

	russia.play();
	return 0;
}

补充说明:
从1.txt里读取方块数据
一个方块数
每个方块长 宽
1,0表示占位
例:可以直接拷贝进1.txt食用:
10

4 2
1 1 1 1
1 0 0 1

4 1
1 1 1 1

4 2
1 1 1 1
0 0 0 1

3 2
1 1 0
0 1 1

2 2
1 1
0 1

2 2
1 0
1 1

2 2
1 1
1 1

3 3
1 1 0
0 1 1
0 0 1

3 3
1 1 1
1 0 1
1 1 1

3 3
1 1 1
1 1 0
1 0 0

其余内容见:https://www.jianshu.com/p/6d9732872d0b

上一篇:APIJSON 博客4 AbstractSQLConfig 第四篇


下一篇:Codeforces Round #717 (Div. 2) C. Baby Ehab Partitions Again