基于VC 6.0 用C语言实现的俄罗斯方块

裸写的俄罗斯方块的代码,有意见或者想征用,直接评论留言即可。

效果如下:


/***************************************************************/
/*俄罗斯方块的实现
* 基于VC 6.0  编译链接即可运行
* 已实现的功能:
* 1、初步的规划及背景图案的显示
* 2、四种方块实现左右移动、下键加速、上键变形(两种变形)功能
* 3、下落方块碰壁及触碰到其它方块的检测
* 4、方块积满一行的消除并加分的功能
* 5、预测方块的功能
* 6、引入set_windows_pos函数解决闪屏问题
* 未解决的缺陷或者代码存在的问题
* 1、预测方块处莫名其妙的出现背景块
* 2、代码耦合性太高,接口封装还是不够好
* 2017.3.22
* 版权:通渭县西关小学四年级一班田刚
*/
/***************************************************************/
#include<stdio.h>
#include<windows.h>
#include<conio.h>
#include<string.h>

#define BACK				176//背景图案
#define BACK_INT            -80//背景的整数表示
#define FRAME               178//分割框图案
#define NODE				219//方块图案
#define NODE_INT            -37//方块的整数表示            
#define ERROR               -1
#define OK                  0

int score = 0;//计分
static int time = 500;//时间,初始为500毫秒
char back[20][30] = {0};//竖直为x轴,横轴为y轴,原点在右上角
int block_type = 0;//方块类型

void backgroud_init(void);//画面背景的初始化
void set_windows_pos(int i, int j);//指定光标位置
void block_display(int block_type, int dir_type, int coor_x, int coor_y, int color_type);//显示或者消除方块
void time_add(void);//加速函数
void block_type_change(void);//方块类型变化
int  block_move_check_x(int block_type, int dir_type, int coor_x, int coor_y);//检测方块是否触到下面已经停止的方块
int  block_move_check_y(int block_type, int dir_type, int coor_x, int coor_y, int dir_block);//检测方块是否触碰到左右的方块
int new_back_y_check(int block_type, int dir_type, int coor_y);//检测方块是否触碰到墙壁 
int block_clear_sort(void);//检测是否满一行,需要消除得分
void block_clear_x(int row);//消除一个满行(都是方块)

int main(void)
{
    int c = 0;
	int new_dir_type = 0;//新的方块方向
	int befor_dir_type = 0;//旧的方块方向
	int new_back_x = 0;//新的方块头坐标x
	int new_back_y = 0;//新的方块头坐标y
	int befor_back_x = 0;//旧的方块头坐标x
	int befor_back_y = -1;//旧的方块头坐标y
	int block_dir = -1;//方块的移动方向

	backgroud_init();//背景的显示

	while(1)
	{
	
		block_type_change();//方块类型变化
		new_back_y = 8;//每次方块从最顶端出现时,其y坐标都为8
        time = 500;
		
        //怎样在这里清除键盘输入,flush不起作用

		for(new_back_x = 0; new_back_x < 20; new_back_x++)
		{
		    befor_dir_type = new_dir_type;
			befor_back_x = new_back_x - 1;
			befor_back_y = new_back_y;
			block_dir = -1;//方块的方向变量初始为-1
			
			block_display(block_type, 0, 17, 26, NODE);//画上预测区域的方块

			if(kbhit())//检测有输入
			{
				c = getch();
				if(c > 0)
				{			 
					switch(c)
					{
						case 119://上
				    			if(0 == new_dir_type)
								{
									new_dir_type = 1;//竖向
								}
								else
								{
									new_dir_type = 0;//横向
								}
                    			break;
						case 97://左
				    			new_back_y--;
								block_dir = 0;
                    			break;
						case 100://右
				    			new_back_y++;
								block_dir = 1;
                    			break;
						case 115://下
								time_add();//加速
                   				break;
						default://ESC
								break;
					}
				}
			}

			new_back_y = new_back_y_check(block_type, new_dir_type, new_back_y);//检查是否触碰到左右壁  
			
			block_display(block_type, befor_dir_type, befor_back_x, befor_back_y, BACK);//原来的方块位置清除掉

			if(-1 != block_dir)//左右移动了方块
			{
				if(ERROR == block_move_check_y(block_type, new_dir_type, new_back_x, new_back_y, block_dir))//检查移动的方块是触碰到左右的方块
				{
					new_back_y = befor_back_y;
				}
			}
			
			block_display(block_type, new_dir_type, new_back_x, new_back_y, NODE);//画下一个方块位置

			if(ERROR == block_move_check_x(block_type, new_dir_type, new_back_x, new_back_y))//检查移动的方块是否触发到下面的方块
			{
				break;
			}
			
			Sleep(time);
		}

		block_display(block_type, 0, 17, 26, BACK);//清楚预测区域的方块	
		
		if(OK == block_clear_sort())//检查下面方块是否等够得分,能得分则消除得分
		{
			set_windows_pos(8, 22);//更新得分
			printf("%d", score);
		}
	}

	return 0;
}

/***************************************************************/
/***  				画面背景的初始化                         ***/
/***其中原点在右上角,竖轴为x轴,横轴为y轴。y(0 - 19)为方块区***/
/***域,20 - 30 为计分区域及方块预测提示区域                 ***/
/***************************************************************/
void backgroud_init(void)
{
	int x = 0, y = 0;

	for(x = 0; x < 20; x++)
	{
		for(y = 0; y < 20; y++)
		{
			back[x][y] = BACK;
		}
	}

	for(x = 0; x < 20; x++)
	{
		for(y = 20; y < 30; y++)
		{
            if((0 == x) || (4 == x) || (10 == x) || (19 == x))
			{
				back[x][y] = FRAME;
			}

			if((20 == y) || (29 == y))
			{
				back[x][y] = FRAME;
			}
		}
	}

	//背景图案的显示
	for(x = 0; x < 20; x++)
	{
		for(y = 0; y < 30; y++)
		{
			printf("%c", back[x][y]);
		}
		
		printf("\n");
	}

	//显示TETRIS
	set_windows_pos(2, 22);//移动windows的光标
	printf("TETRIS\n");

	//显示积分
	set_windows_pos(6, 22);//移动windows的光标
	printf("SORT\n");
    set_windows_pos(8, 22);
	printf("%d\n", score);

	//显示下一个要出现的方块
    set_windows_pos(12, 22);//移动windows的光标
	printf("EXPECT\n");
}

/***************************************************************/
/***  		设置windows光标,类似于TC中的gotoxy              ***/
/***i,j 为要传入的x,y坐标									 ***/
/***************************************************************/
void set_windows_pos(int i, int j)//设置windows光标,类似于TC中的gotoxy
{  
    /*if((0 > i) || (0 > j))
	{
		return ERROR;
	}*/

    /*windows的横轴是x轴,而本程序设计的是竖轴是X轴
	 这里做个转换*/
	COORD pos={j,i};
	HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleCursorPosition(hOut,pos);
}   

/***************************************************************/
/***********************消除/填上方块***************************/
/***输入:block_type 方块类型  1:长条  2:2型  3:7型  4:田型***/
/***输入:dir_type 方向类型  0:横向  1:竖向                 ***/
/***输入:coor_x coor_y   方块当前头的坐标                    ***/
/***输入:color_type    图标类型   BACK 背景色  NODE 方块色   ***/
/***初始coor_x,coor_y为一个方块的最右下的一个方块的坐标      ***/
/***************************************************************/
void block_display(int block_type, int dir_type, int coor_x, int coor_y, int color_type)
{
    int x = 0, y = 0;

	switch (block_type)
	{
		case 1://长条
			if(0 == dir_type)//横向
			{
				for(y = coor_y; y >= (coor_y - 3); y--)
				{
					back[coor_x][y] = color_type;//方块色
					set_windows_pos(coor_x, y);//移动windows的光标
					printf("%c", back[coor_x][y]);
				}
			}
			else if(1 == dir_type)//竖向
			{
				for(x = coor_x; (x >= (coor_x - 3)) && (x >= 0); x--)
				{
					back[x][coor_y] = color_type;//方块色
					set_windows_pos(x, coor_y);//移动windows的光标
					printf("%c", back[x][coor_y]);
				}
			}
			else
			{
				printf("dir_type is error!\n");
			}
			break;
		case 2://2型
			if(0 == dir_type)//横向
			{
				for(y = coor_y; y >= coor_y - 1; y--)
				{
					back[coor_x][y] = color_type;//方块色
					set_windows_pos(coor_x, y);//移动windows的光标
					printf("%c", back[coor_x][y]);
				}
				
				coor_x--;
				coor_y--;

				if(coor_x < 0)
				{
					return;
				}
				
				for(y = coor_y; y >= coor_y - 1; y--)
				{
					back[coor_x][y] = color_type;//方块色
					set_windows_pos(coor_x, y);//移动windows的光标
					printf("%c", back[coor_x][y]);
				}
			}
			else if(1 == dir_type)//竖向
			{
				for(x = coor_x; (x >= coor_x - 1) && (x >= 0); x--)
				{
					back[x][coor_y] = color_type;//方块色
					set_windows_pos(x, coor_y);//移动windows的光标
					printf("%c", back[x][coor_y]);	
				}
				
				coor_x--;
				coor_y--;

				if(coor_x < 0)
				{
					return;
				}
				
				for(x = coor_x; x >= coor_x - 1; x--)
				{
					back[x][coor_y] = color_type;//方块色
					set_windows_pos(x, coor_y);//移动windows的光标
					printf("%c", back[x][coor_y]);	
				}
			}
			else
			{
				printf("dir_type is error!\n");
			}
			break;
		case 3://7型
			if(0 == dir_type)//横向
			{
				for(y = coor_y; y >= coor_y - 2; y--)
				{
					back[coor_x][y] = color_type;//方块色
					set_windows_pos(coor_x, y);//移动windows的光标
					printf("%c", back[coor_x][y]);
				}
				
				coor_x--;
				coor_y = coor_y - 2;

				if(coor_x < 0)
				{
					return;
				}
				
				back[coor_x][coor_y] = color_type;//方块色
				set_windows_pos(coor_x, coor_y);//移动windows的光标
				printf("%c", back[coor_x][coor_y]);
			}
			else if(1 == dir_type)//竖向
			{
				for(x = coor_x; (x >= coor_x - 2) && (x >= 0); x--)
				{
					back[x][coor_y] = color_type;//方块色
					set_windows_pos(x, coor_y);//移动windows的光标
					printf("%c", back[x][coor_y]);
				}
				
				coor_x = coor_x - 2;
				coor_y--;
				
                if(coor_x < 0)
				{
					return;
				}

				back[coor_x][coor_y] = color_type;//方块色
				set_windows_pos(coor_x, coor_y);//移动windows的光标
				printf("%c", back[coor_x][coor_y]);
				
			}
			else
			{
				printf("dir_type is error!\n");
			}
			break;
		case 4://田型
			if((0 == dir_type) || (1 == dir_type))//横向
			{
				for(y = coor_y; y >= coor_y - 1; y--)
				{
					back[coor_x][y] = color_type;//方块色
					set_windows_pos(coor_x, y);//移动windows的光标
					printf("%c", back[coor_x][y]);
				}
				
				coor_x--;

				if(coor_x < 0)
				{
					return;
				}
				
				for(y = coor_y; y >= coor_y - 1; y--)
				{
					back[coor_x][y] = color_type;//方块色
					set_windows_pos(coor_x, y);//移动windows的光标
					printf("%c", back[coor_x][y]);
				}
			}
			else
			{
				printf("dir_type is error!\n");
			}
			break;
		default:
			printf("block_type is  error!\n");
			break;
	}
}

void time_add(void)//加速函数
{
	if(500 == time)
	{
		time = 100;//减少的100毫秒
	}
	else if(100 == time)
	{
		time = 500;
	}
	else
	{
		;//暂时留空
	}
}

void block_type_change(void)//方块类型变化
{
	block_type++;
	
	if(block_type > 4)
	{
		block_type = 1;
	}
}

/***************************************************************/
/*******************方块y坐标撞墙检测***************************/
/***输入:block_type 方块类型  1:长条  2:2型  3:7型  4:田型***/
/***输入:dir_type 方向类型  0:横向  1:竖向                 ***/
/***输入:coor_y   方块当前头(右下角第一个方块)的坐标         ***/
/***************************************************************/
int new_back_y_check(int block_type, int dir_type, int coor_y)
{
	if(coor_y > 19)
	{
		coor_y = 19;
	}
	
	switch (block_type)
	{
		case 1://长条
			if(0 == dir_type)//横向
			{	
				if(coor_y - 3 < 0)
				{
					coor_y = 3;
				}
			}
			else if(1 == dir_type)//竖向
			{
				if(coor_y < 0)
				{
					coor_y = 0;
				}
			}
			else
			{
				printf("dir_type is error!\n");
			}
			break;
		case 2://2型
			if(0 == dir_type)//横向
			{
				if(coor_y - 2 < 0)
				{
					coor_y = 2;
				}
			}
			else if(1 == dir_type)//竖向
			{
				if(coor_y - 1 < 0)
				{
					coor_y = 1;
				}
			}
			else
			{
				printf("dir_type is error!\n");
			}
			break;
		case 3://7型
			if(0 == dir_type)//横向
			{
				if(coor_y - 2 < 0)
				{
					coor_y = 2;
				}
			}
			else if(1 == dir_type)//竖向
			{
				if(coor_y - 1 < 0)
				{
					coor_y = 1;
				}
			}
			else
			{
				printf("dir_type is error!\n");
			}
			break;
		case 4://田型
			if((0 == dir_type) || (1 == dir_type))//横向
			{
				if(coor_y - 1 < 0)
				{
					coor_y = 1;
				}
			}
			else
			{
				printf("dir_type is error!\n");
			}
			break;
		default:
			printf("block_type is  error!\n");
			break;
	}
	
	return coor_y;
}

/*
检查方块是否触到下面已经停止的方块,触碰到就返回ERROR
*/
/***************************************************************/
/****检查方块是否触到下面已经停止的方块,触碰到就返回ERROR   ***/
/***输入:block_type 方块类型  1:长条  2:2型  3:7型  4:田型***/
/***输入:dir_type 方向类型  0:横向  1:竖向                 ***/
/***输入:coor_x coor_y   方块当前头的坐标                    ***/
/***初始coor_x,coor_y为一个方块的最右下的一个方块的坐标      ***/
/***************************************************************/
int block_move_check_x(int block_type, int dir_type, int coor_x, int coor_y)
{
	int ret = OK;
	int x = 0, y = 0;
	
	switch (block_type)
	{
		case 1://长条
			if(0 == dir_type)//横向
			{	
				for(y = coor_y; y >= coor_y - 3; y--)
				{
					if(NODE_INT == back[coor_x + 1][y])
					{
						ret = ERROR;
						break;
					}
				}
			}
			else if(1 == dir_type)//竖向
			{
				if(NODE_INT == back[coor_x + 1][coor_y])
				{
					ret = ERROR;
				}
			}
			else
			{
				printf("dir_type is error!\n");
			}
			break;
		case 2://2型
			if(0 == dir_type)//横向
			{
				for(y = coor_y; y >= coor_y - 1; y--)
				{
					if(NODE_INT == back[coor_x + 1][coor_y])
					{
						ret = ERROR;
						break;
					}
				}
				
				coor_x--;
				coor_y =coor_y - 2 ;
				
				if(NODE_INT == back[coor_x + 1][coor_y])
				{
					ret = ERROR;
				}
			}
			else if(1 == dir_type)//竖向
			{
				if(NODE_INT == back[coor_x + 1][coor_y])
				{
					ret = ERROR;
				}
				
				coor_x--;
				coor_y--;
				
				if(NODE_INT == back[coor_x + 1][coor_y])
				{
					ret = ERROR;
				}
			}
			else
			{
				printf("dir_type is error!\n");
			}
			break;
		case 3://7型
			if(0 == dir_type)//横向
			{
				for(y = coor_y; y >= coor_y - 2; y--)
				{
					if(NODE_INT == back[coor_x + 1][y])
					{
						ret = ERROR;
						break;
					}
				}
			}
			else if(1 == dir_type)//竖向
			{
				if(NODE_INT == back[coor_x + 1][coor_y])
				{
					ret = ERROR;
				}
				
				coor_x = coor_x - 2;
				coor_y--;
				
				if(NODE_INT == back[coor_x + 1][coor_y])
				{
					ret = ERROR;
				}
			}
			else
			{
				printf("dir_type is error!\n");
			}
			break;
		case 4://田型
			if((0 == dir_type) || (1 == dir_type))//横向
			{
				for(y = coor_y; y >= coor_y - 1; y--)
				{
					if(NODE_INT == back[coor_x + 1][y])
					{
						ret = ERROR;
						break;
					}
				}
			}
			else
			{
				printf("dir_type is error!\n");
			}
			break;
		default:
			printf("block_type is  error!\n");
			break;
	}
			
	return ret;
}

/***************************************************************/
/****检查方块在向下移动的过程中是否触到左右的方块            ***/
/***输入:block_type 方块类型  1:长条  2:2型  3:7型  4:田型***/
/***输入:dir_type 方向类型  0:横向  1:竖向                 ***/
/***输入:coor_x coor_y   方块当前头(右下)的坐标            ***/
/***输入:dir_block    当前方块的移动方向(左右)   			 ***/
/***************************************************************/
int block_move_check_y(int block_type, int dir_type, int coor_x, int coor_y, int dir_block)
{
	int x = 0, y = 0;
	int ret = OK;

	switch (block_type)
	{
		case 1://长条
			if(0 == dir_type)//横向
			{	
				if(1 == dir_block)//右移
				{	
					if(NODE_INT == back[coor_x][coor_y])
					{
						ret = ERROR;
					}
				}
				else if(0 == dir_block)//左移
				{
					if(NODE_INT == back[coor_x][coor_y - 3])
					{
						ret = ERROR;
					}
				}
				else
				{
					printf("dir_block is error!");
				}
			}
			else if(1 == dir_type)//竖向
			{
				//当长条为竖向时,不用判断长条是往左移还是往右移
				for(x = coor_x; x >= coor_x - 3; x--)
				{
					if(NODE_INT == back[x][coor_y])
					{
						ret = ERROR;
						break;
					}
				}
			}
			else
			{
				printf("dir_type is error!\n");
			}
			break;
		case 2://2型
			if(0 == dir_type)//横向
			{	
				if(1 == dir_block)//右移
				{	
					if(NODE_INT == back[coor_x][coor_y])
					{
						ret = ERROR;
						break;
					}
					
					if(NODE_INT == back[coor_x - 1][coor_y - 1])
					{
						ret = ERROR;
					}
				}
				else if(0 == dir_block)//左移
				{
					if(NODE_INT == back[coor_x][coor_y - 1])
					{
						ret = ERROR;
						break;
					}
					
					if(NODE_INT == back[coor_x - 1][coor_y - 2])
					{
						ret = ERROR;
					}
				}
				else
				{
					printf("dir_block is error!");
				}
			}
			else if(1 == dir_type)//竖向
			{
				if(1 == dir_block)//右移
				{	
					for(x = coor_x; x >= coor_x - 1; x--)
					{
						if(NODE_INT == back[x][coor_y])
						{
							ret = ERROR;
							break;
						}	
					}
					
					if(NODE_INT == back[coor_x - 2][coor_y - 1])
					{
						ret = ERROR;
					}
				}
				else if(0 == dir_block)//左移
				{
					if(NODE_INT == back[coor_x][coor_y])
					{
						ret = ERROR;
						break;
					}
					
					coor_x--;
					coor_y--;
					
					for(x = coor_x; x >= coor_x - 1; x--)
					{
						if(NODE_INT == back[x][coor_y])
						{
							ret = ERROR;
							break;
						}
					}
				}
				else
				{
					printf("dir_block is error!");
				}	
			}
			else
			{
				printf("dir_type is error!\n");
			}
			break;
		case 3://7型
			if(0 == dir_type)//横向
			{
				if(1 == dir_block)//右移
				{	
					if(NODE_INT == back[coor_x][coor_y])
					{
						ret = ERROR;
						break;
					}
					
					if(NODE_INT == back[coor_x - 1][coor_y - 2])
					{
						ret = ERROR;
					}
				}
				else if(0 == dir_block)//左移
				{
					if(NODE_INT == back[coor_x][coor_y - 2])
					{
						ret = ERROR;
						break;
					}
					
					if(NODE_INT == back[coor_x - 1][coor_y - 2])
					{
						ret = ERROR;
					}
				}
				else
				{
					printf("dir_block is error!");
				}
			}
			else if(1 == dir_type)//竖向
			{
				if(1 == dir_block)//右移
				{	
					for(x = coor_x; (x >= coor_x - 2) && (x >= 0); x--)
					{
						if(NODE_INT == back[x][coor_y])
						{
							ret = ERROR;
							break;
						}
					}
				}
				else if(0 == dir_block)//左移
				{
					for(x = coor_x - 1; (x >= coor_x - 2) && (x >= 0); x--)
					{
						if(NODE_INT == back[x][coor_y])
						{
							ret = ERROR;
							break;
						}
					}
				
					coor_x = coor_x - 2;
					coor_y--;

					if(NODE_INT == back[coor_x][coor_y])
					{
						ret = ERROR;
					}
				}
				else
				{
					printf("dir_block is error!");
				}
			}
			else
			{
				printf("dir_type is error!\n");
			}
			break;
		case 4://田型
			if((0 == dir_type) || (1 == dir_type))//横向
			{
				if(1 == dir_block)//右移
				{	
					for(x = coor_x; x >= coor_x - 1; x--)
					{
						if(NODE_INT == back[x][coor_y])
						{
							ret = ERROR;
							break;
						}
					}
				}
				else if(0 == dir_block)//左移
				{
					for(x = coor_x; x >= coor_x - 1; x--)
					{
						if(NODE_INT == back[x][coor_y - 1])
						{
							ret = ERROR;
							break;
						}
					}
				}
				else
				{
					printf("dir_block is error!");
				}
			}
			else
			{
				printf("dir_type is error!\n");
			}
			break;
		default:
			printf("block_type is  error!\n");
			break;
	}
			
	return ret;
}

void block_clear_x(int row)//消除某一行
{
	int x = 0, y = 0;
	
	char back_replace[20][30] = {0};//替代back
	
	memcpy(back_replace, back, sizeof(back));//将back暂存到back_replace中
	
	for(x = 0; x <= row; x++)
	{
		for(y = 0; y < 20; y++)
		{
			back[x][y] = BACK;//初始化未背景色
		}
	}

	for(x = row; x >= 1; x--)
	{
		for(y = 0; y < 20; y++)
		{	
			back[x][y] = back_replace[x - 1][y];//消除一行,方块下沉
		}
	}

	set_windows_pos(0, 0);//移动windows的光标

	for(x = 0; x < 20; x++)
	{
		for(y = 0; y < 20; y++)
		{
			printf("%c", back[x][y]);
		}
		
		printf("\n");
	}
}

/*
检查是否消行并且进行计分
*/
int block_clear_sort(void)
{
	int x = 0, y = 0;
	int ret = ERROR;
	int flag = 0;
	
	for(x = 19; x >= 0; x--)//行
	{
		flag = 0;
		
		for(y = 0; y < 20; y++)
		{
			if(NODE_INT == back[x][y])
			{	
				flag++;//一行的块计数
			}
			
			if(20 == flag)//表示一行有20个方块
			{
				block_clear_x(x);//消行
				score++;//加分
				ret = OK;
			}
		}
	}
	
	return ret;
}


  • 5
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值