俄罗斯方块C语言版(linux下)

#include <fcntl.h> 
#include <stdlib.h>
#include <stdio.h>
#define TTY_PATH  "/dev/tty"
#define STTY_US  "stty raw -echo -F "
#define STTY_DEF  "stty -raw echo -F "

struct Point//坐标类型
{
	int x;
	int y;
};

struct Shap//图形类型
{
	struct Point points[4];
};

//图形库
struct Shap shaps[19] = {
	{{{0,0},{-1,0},{1,0},{2,0}}},//横条
	{{{0,0},{0,-1},{0,1},{0,2}}},//竖条
	{{{0,0},{-1,-1},{-1,0},{0,-1}}},//方块
	{{{0,0},{0,-1},{0,-2},{1,0}}},//正L1
	{{{0,0},{0,1},{1,0},{2,0}}},//正L2
	{{{0,0},{-1,0},{0,1},{0,2}}},//正L3
	{{{0,0},{0,-1},{-1,0},{-2,0}}},//正L4
	{{{0,0},{-1,0},{0,-1},{0,-2}}},//反L1
	{{{0,0},{0,-1},{1,0},{2,0}}},//反L2
	{{{0,0},{1,0},{0,1},{0,2}}},//反L3
	{{{0,0},{-1,0},{-2,0},{0,1}}},//反L4
	{{{0,0},{-1,0},{1,0},{0,-1}}},//T1
	{{{0,0},{0,1},{0,-1},{1,0}}},//T2
	{{{0,0},{-1,0},{1,0},{0,1}}},//T3
	{{{0,0},{-1,0},{0,-1},{0,1}}},//T4
	{{{0,0},{1,0},{0,-1},{-1,-1}}},//正Z1
	{{{0,0},{1,-1},{0,1},{1,0}}},//正Z2
	{{{0,0},{1,-1},{-1,0},{0,-1}}},//反z1
	{{{0,0},{-1,-1},{-1,0},{0,1}}}//反Z2
};

#define WIDTH	20
#define HEIGHT	30

#define CHANGE	'w'
#define RIGHT	'd'
#define LEFT	'a'
#define DOWN	's'
#define CTRL_C	3

struct Point position = {WIDTH/2, 2};//图形的坐标位置
struct Shap nowShap;//表示当前的图形
int nowShapIndex;//当前图形在图形库中的角标
int staticShapes[HEIGHT+2][WIDTH+2] = {
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0},
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0},
	{0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0},
	{0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0},
	{0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0},
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0},
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0},
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0},
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0},
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0},
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0},
	{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
};//保存下落后的静态图形  每个元素表示屏幕上的一个点 0该点没有图形 1该点有图形

int get_char();	//能实现非阻塞IO, 如果没有按下按键,程序继续往下走   
void drowPoint(int x, int y);
void drowStar(int x, int y);

void drawFrame();
void userCtrl();
void createShap();
void drawShap();
void moveDown();
int collide(struct Shap shap);
void addShapToStatic();
void drawStaitcShapes();
void clearLines();

int main()
{
	srand(time(0));//初始化随机种子  只初始化一次
	system( STTY_US  TTY_PATH ); 
	createShap();//创建一个图形
	while(1)
	{
		system("clear");
		drawShap();
		drawStaitcShapes();
		drawFrame();
		userCtrl();
		moveDown();
		fflush(stdout);
		usleep(100000);//50毫秒  每秒20帧
	}
	return 0;
}

//创建图形
void createShap()
{
	position.x = WIDTH/2;
	position.y = 2;
	//nowShapIndex = rand()%19;//随机一个图形的角标
	nowShapIndex = 0;
	nowShap = shaps[nowShapIndex];//随机一个图形
}

//自然下落
int moveDownSpeed = 0;

void moveDown()
{
	if(++moveDownSpeed == 5)
	{
		//计算出假设移动后的图形
		struct Shap shap = nowShap;
		int i;
		for(i = 0;i < 4;i++)
		{
			shap.points[i].x += position.x;
			shap.points[i].y += position.y+1;
		}
		//如果没有碰撞,才向下移动
		if(collide(shap)==0)
		{		
			position.y++;	
		}
		else//到底了
		{
			addShapToStatic();//将图形加入到静态
			clearLines();
			createShap();//创建新图形
		}
		moveDownSpeed = 0;
	}
}

//变形
void changeShap()
{
	int index = nowShapIndex;
	switch(nowShapIndex)
	{
	case 0://横条
		index++;
		break;
	case 1://竖条
		index = 0;
		break;
	case 2://方块
		break;
	case 3://正L1
	case 4:
	case 5:
		index++;
		break;
	case 6://正L4
		index = 3;//变回正L1
		break;
	case 7://反L1
	case 8:
	case 9:
		index++;
		break;
	case 10://反L4
		index = 7;//变回反L1
		break;
	case 11://T 1
	case 12:
	case 13:
		index++;
		break;
	case 14://T 4
		index = 11;//变回T 1
		break;
	case 15://zz1
		index = 16;
		break;
	case 16://zz2
		index = 15;
		break;
	case 17://fz1
		index = 18;
		break;
	case 18://fz2
		index = 17;
		break;
	}
	//假设变形
	struct Shap shap = shaps[index];
	int i;
	for(i = 0;i < 4;i++)
	{
		shap.points[i].x += position.x;
		shap.points[i].y += position.y;
	}
	//如果变形后不碰撞,才变形
	if(collide(shap) == 0)
	{
		nowShapIndex = index;
		nowShap = shaps[index];
	}
}

//将图形加入到静态数组中
void addShapToStatic()
{
	int i;//遍历图形中的4个点,找到staticShapes中的对应元素,置1
	for(i = 0;i < 4;i++)
	{
		int x = nowShap.points[i].x+position.x;
		int y = nowShap.points[i].y+position.y;
		staticShapes[y][x] = 1;
	}
}

//显示静态图形
void drawStaitcShapes()
{
	int i, j;
	for(i = 0;i < HEIGHT+2;i++)//外层循环遍历y轴
	{
		for(j = 0;j < WIDTH+2;j++)//内层循环遍历X轴
		{
			if(staticShapes[i][j] == 1)//这个点是有图形的
			{
				drowPoint(j, i);//j是x   i是y
			}
		}
	}
}

//绘制一个图形
void drawShap()
{
	int i;
	for(i = 0;i < 4;i++)
	{
		drowPoint(position.x+nowShap.points[i].x, position.y+nowShap.points[i].y);
	}
}

//碰撞判定
//参数:判断的图形
//返回值  1 碰撞  0没有碰撞
int collide(struct Shap shap)
{
	int i;
	for(i = 0;i < 4;i++)
	{
		int x = shap.points[i].x;
		int y = shap.points[i].y;
		if(shap.points[i].x < 1 //左边
			|| shap.points[i].x > WIDTH//右边
			|| shap.points[i].y > HEIGHT//下边
			|| staticShapes[y][x]==1	//
			)
		{
			return  1;
		}
	}
	return 0;
}

//判断一行是否满
//参数:行号
//返回值:1 满  0不满
int isLineFull(int line)
{
	int i;
	for(i = 1;i < WIDTH+1;i++)
	{
		if(staticShapes[line][i] == 0)
		{
			return 0;
		}
	}
	return 1;
}

//行赋值
//参数1和参数2是两个行号  line2覆盖 line1
void lineCpy(int line1, int line2)
{
	int i;
	for(i = 1;i < WIDTH+1;i++)
	{
		staticShapes[line1][i] = staticShapes[line2][i];
	}
}

//将整行置0
//参数:行号
void setLine(int line)
{
	int i;
	for(i = 1;i < WIDTH+1;i++)
	{
		staticShapes[line][i] = 0;
	}
}

//消行
void clearLines()
{
	int mark[HEIGHT+2] = {0};//存放标记的数组,因为一共HEIGHT+2行  0 和HEIGHT+1是边界
	int i;
	int count = 0;
	//统计每一行应该移动的距离
	for(i = HEIGHT;i > 1;i--)//从底行向上遍历
	{
		if(isLineFull(i) == 1)//找到了满行
		{
			mark[i] = -1;
			count++;
		}
		else
		{
			mark[i] = count;
		}
	}

	//移动
	for(i = HEIGHT;i > 1;i--)
	{
		int len = mark[i];
		if(mark[i] == -1)//这是要被消掉的行,不用挪动
		{
			continue;
		}
		if(len > 0)
		{
			lineCpy(i+len, i);//ii+len行被 i行覆盖
			setLine(i);//挪一行就清一行
		}
	}

	//清空后面的行  一共需要清理count行,行号从1开始
	/*for(i = 0;i < count;i++)
	{
		setLine(i+1);
	}*/
}


//绘制游戏边框
void drawFrame()
{
	int i;
	//最上面一行
	for(i = 0;i < WIDTH+2;i++)
	{
		drowStar(i, 0);
		drowStar(i, HEIGHT+1);
	}

	for(i = 0;i < HEIGHT+2;i++)
	{
		drowStar(0, i);
		drowStar(WIDTH+1, i);
	}
}

//用户输入并控制坐标
void userCtrl()
{
	struct Shap shap = nowShap;
	int i;
	switch(get_char())
	{
	case CHANGE://变形
		changeShap();
		break;
	case DOWN:
		break;
	case RIGHT:
		for(i = 0;i < 4;i++)
		{
			shap.points[i].x += position.x+1;
			shap.points[i].y += position.y;
		}
		if(collide(shap) == 0)
		{
			position.x++;
		}
		break;
	case LEFT:
		for(i = 0;i < 4;i++)
		{
			shap.points[i].x += position.x-1;
			shap.points[i].y += position.y;
		}
		if(collide(shap) == 0)
		{
			position.x--;
		}
		break;
	case CTRL_C:
		system(STTY_DEF TTY_PATH);
		exit(0);//结束程序
		break;
	}
}

void drowPoint(int x, int y)
{
	printf("\033[%d;%dH", y+1, x*2+1);
	printf("\033[1;36m■ \033[0m");
}

void drowStar(int x, int y)
{
	printf("\033[%d;%dH", y+1, x*2+1);
	printf("\033[1;36m* \033[0m");
}

int get_char()	//能实现非阻塞IO, 如果没有按下按键,程序继续往下走   
{
  fd_set rfds;
  struct timeval tv;
  int ch = 0;
  FD_ZERO(&rfds);
  FD_SET(0, &rfds);
  tv.tv_sec = 0;
  tv.tv_usec = 10; //设置等待超时时间
  //检测键盘是否有输入
  if (select(1, &rfds, NULL, NULL, &tv) > 0)
  {
      ch = getchar(); 
  }
  return ch;
}
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

encounter♌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值