【小游戏】俄罗斯方块(C++版)

大一作品,留念
#include<stdio.h>
#include<time.h>
#include<conio.h>//kbhit
#include<stdlib.h>//rand,srand
#include<windows.h>
#define wide 15
#define hight 18
#define period 500
typedef struct point
{
	int h;
	int w;
}point;

/*
1 ■■■■                 1*4 -> 4*1

  ■             ■
  2■■■   3 ■■■         2*3 -> 3*2


	  ■■          ■■       2*3 -> 3*2
	  4 ■■         5     ■■


		  ■■             ■
		  6 ■■   2*2  7  ■■■      2*3->3*2

			最大面积为4*4
			1234		■■■■
			1234		■■■■
			1234		■■■■
			1234		■■■■
			按W键旋转九十度




*/

char map[hight][wide]={0};//1:□ 2:■  其余的都是空格 char类型节约空间
char stay[hight][wide]={0};//残留方块
struct point size;//活动方块的大小 前一个代表 高度 后一个代表 宽度 ,主要用于触碰处理
char sqr[4][4];//活动方块数组
struct point posi={1,wide/2-2};//方块顶点坐标
char situ=0;//旋转状况0 正常 1 顺时针90度 2:180 3:270
int grade=0,line=0;
//char sqr[4][4];
//point newspr={1,wide/2};
//------------函数声明
	void showmap();
	void setmap();
    int keypre(char k);//按下某键
	int getrand(int,int);//取一个范围内的随机数
	int setini(int type);//初始化方块,类型,看表吧
	void turn90();
	int isagain();//判断活动区是否与stay区重复
	int exsqr(char row);//判断stay区某一行是否存在方块,存在返回1,不存在返回0
	void judge();//层满处理
int main()
{
	int last=0,t;
    int i;
	srand(time(NULL));

	//随机图形
	setini(getrand(1,7));




	//屏幕渲染
	do
	{
		t=clock();
		if(t-last>=period)
		{
			//周期性刷新
			last=t;
			system("cls");
			if(keypre('s')==0)
				break;

			setmap();
			printf("-----------当前分数:%d,已消除行:%d-----------\n",grade,line);
			showmap();

		}
		if(kbhit()==1)
		{
			system("cls");
			if(keypre(getch())==0)
				break;
			setmap();
			printf("-----------当前分数:%d,已消除行:%d-----------\n",grade,line);
			showmap();

		}

	}while(1);

	system("cls");
	printf("----------------得分:%d   消除:%d-------------------\n",grade,line);
	setmap();
	showmap();
	printf("----------------游戏结束!谢谢玩耍!----------------\n");
	printf("按回车键退出!\n");
	while(getchar()!='\n');
	return 0;
}


int keypre(char k)//按下某键
{
	int i,j,real=0;
	char top[wide];
	if(k=='s')
	{
		posi.h++;
		if(isagain())//下一步是否会重合
			real=1;//那么下一步不能走了
		//留在当前位置
		if(real)
		{
			grade+=18;//留步加分
			posi.h--;//留在上一步
			for(i=0;i<size.h ;i++)//就留下来了
			{
				for(j=0;j<size.w;j++)
				{
					if(sqr[i][j]==2)//只记录实体
						stay[i+posi.h][j+posi.w ]=2;
				}
			}
			//出新的
			judge();//层满判断
			return (setini(getrand(1,7)));
		}
	}
	else if(k=='a'||k=='A')
	{
		posi.w --;
		if(isagain())
			posi.w ++;//移动取消
	}
	else if(k=='d'||k=='D')
	{
		posi.w ++;
		if(isagain())
			posi.w --;//移动取消
	}
	else if(k=='w'||k=='W')
		turn90();
	else if(k=='s'||k=='S')
	{
		posi.h++;
		if(isagain())
			posi.h --;//移动取消
	}
	//左右分界判断
	if(posi.w+size.w>wide-1)
		posi.w=wide-1-size.w;
	if(posi.w <1)
		posi.w=1;
	return 1;

}
void setmap()//初始化地图,并置
{
	int i,j;
	//画地图区域
	for(i=0;i<hight;i++)
	{
		for(j=0;j<wide;j++)
		{
			if(i==0||i==hight-1||j==0||j==wide-1)
				map[i][j]=1;//边界
			else
				map[i][j]=0;//空白
		}
	}

	//画活动方块
	for(i=0;i<size.h ;i++)
	{
		for(j=0;j<size.w ;j++)
		{
			map[posi.h+i][posi.w+j]=sqr[i][j];
		}
	}
	//画残留
	for(i=0;i<hight;i++)
	{
		for(j=0;j<wide;j++)
		{
			if(stay[i][j]==2)
				map[i][j]=2;
		}
	}
}
//将数组转换为图形
void showmap()
{
	int i,j;
	for(i=0;i<hight;i++)
	{
		for(j=0;j<wide;j++)
		{
			if(map[i][j]==1)
				printf("□");
			else if(map[i][j]==2)
				printf("■");
			else
				printf("  ");

		}
		printf("\n");
	}
}

int getrand(int min,int max)//取一个范围内的随机数
{
	return (min+rand()%(max-min+1));
}

void turn90()//活动方块顺时针旋转九十度
{
	int i,j;
	char a[4][4];//临时变量
    char temp[4][4];
    //方块备份
    for(i=0;i<4;i++)
		for(j=0;j<4;j++)
			temp[i][j]=sqr[i][j];

	for(i=0;i<4;i++)
		for(j=0;j<4;j++)
			a[j][i]=sqr[i][j];//斜线对称


	//左右对称,即是转动九十度
	i=size.h ;
	size.h =size.w;
	size.w =i;
	for(i=0;i<size.h ;i++)
		for(j=0;j<size.w ;j++)
			sqr[i][size.w-1-j]=a[i][j];

    if(isagain())
        for(i=0;i<4;i++)
            for(j=0;j<4;j++)
                sqr[i][j]=temp[i][j];


}

int setini(int type)//初始化方块,类型,看表吧
{
	int i,j;
	for(i=0;i<4;i++)
		for(j=0;j<4;j++)
			sqr[i][j]=0;//归零
		switch(type)
		{
		case 1:
			size.h =1;
			size.w =4;
			sqr[0][0]=2;
			sqr[0][1]=2;
			sqr[0][2]=2;
			sqr[0][3]=2;
			break;
		case 2:
			size.h =2;
			size.w =3;
			sqr[0][0]=2;
			sqr[1][0]=2;
			sqr[1][1]=2;
			sqr[1][2]=2;
			break;
		case 3:
			size.h =2;
			size.w =3;
			sqr[0][2]=2;
			sqr[1][0]=2;
			sqr[1][1]=2;
			sqr[1][2]=2;
			break;
		case 4:
			size.h =2;
			size.w =3;
			sqr[0][1]=2;
			sqr[0][2]=2;
			sqr[1][0]=2;
			sqr[1][1]=2;
			break;
		case 5:
			size.h =2;
			size.w =3;
			sqr[0][0]=2;
			sqr[0][1]=2;
			sqr[1][1]=2;
			sqr[1][2]=2;
			break;
		case 6:
			size.h =2;
			size.w =2;
			sqr[0][0]=2;
			sqr[0][1]=2;
			sqr[1][0]=2;
			sqr[1][1]=2;
			break;
		case 7:
			size.h =2;
			size.w =3;
			sqr[0][1]=2;
			sqr[1][0]=2;
			sqr[1][1]=2;
			sqr[1][2]=2;
			break;
		}
		posi.h =1;
		posi.w =(wide-size.w )/2;
		if(isagain())//刚刚初始化你就重合了,你说你是不是挂了?
			return 0;
		return 1;
		/*	1 ■■■■                 1*4 -> 4*1

		   ■             ■
		  2■■■   3 ■■■         2*3 -> 3*2


			  ■■          ■■       2*3 -> 3*2
			  4 ■■     5    ■■


				    ■■             ■
				  6 ■■   2*2  7  ■■■      2*3->3*2
		*/
}
void judge()//层满处理
{
	int i,j,full,k,esqr;
	for(i=1;i<hight-1;i++)//除掉边界
	{
		full=1;
		for(j=1;j<wide-1;j++)//除掉边界
		{
			if(stay[i][j]!=2)//存在不为方块的
				full=0;//假空
		}
		if(full)//真空
		{
			line++;//已消除
			grade+=90;//消除加五倍分数
			for(j=1;j<wide-1;j++)//除掉边界
				stay[i][j]=0;//置零
		}

	}
	//全部除完之后
	for(i=hight-2;i>=2;i--)
	{
	    int s=i;
		if(exsqr(i)==0)//本层为空
		{
		    //上层下移
			while(s>=1 && exsqr(--s)==0)
                //该层不存在方块
                //继续向上寻找
                ;
			for(j=1;j<wide-1;j++)
			{
				stay[i][j]=stay[s][j];//上层下移
				stay[s][j]=0;//上层清空
			}

		}
	}
}

int isagain()//判断活动区是否与stay区重复
{
	int i,j;
	for(i=0;i<size.h ;i++)
	{
		for(j=0;j<size.w ;j++)
		{
			if(sqr[i][j]==2)//是实体,i,j是框内代号
			{
			    if(posi.h +i >hight-2)
                    return 1;
			    else if(stay[posi.h +i][posi.w +j]==2)//框内位置转换为map位置
					return 1;

			}
		}
	}
	return 0;//未重复

}

int exsqr(char row)//判断stay区某一行是否存在方块,存在返回1,不存在返回0
{
	int j;
	for(j=1;j<wide-1;j++)//出掉边界
		if(stay[row][j]==2)
			return 1;
	return 0;
}

转载于:https://www.cnblogs.com/tinyjian/p/6550718.html

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值