#include
#include
#include
#include
void gotoxy(int x,int y);//控制光标。X表示横坐标,Y表示纵坐标
void console();//设置控制台窗口大小,为了让程序运行得更好看
void my_print();//设置界面
void my_randout();//随机出现方块,并打印在提示区
void my_printblock();//打印 4*4 的方格来显示方块
void my_up();//旋转
void my_down();//下移
void my_lift();//左移
void my_right();//右移
void clear();//消除整行
void gameover();//游戏结束
void my_stop();//游戏暂停
int tem[4][4];//用4*4的方格来控制方块的操作和显示 这个作为传值媒介
int block[4][4];//提示区的方块
int BLOCK[4][4];//正在下落的方块
int scope[25][34] = {0};//操作的范围 这里要注意,一个方格是占两个横坐标单位的
int point_x , point_y;//方格的左上角坐标
int fen = 0;//得分
bool check = true;//检查方块还能不能下落
int block0[4][4] = {{0,1,1,0},{0,0,1,0},{0,0,1,0},{0,0,0,0}};// 7 个方块 用数组表示 正“7”
int block1[4][4] = {{0,1,1,0},{0,1,0,0},{0,1,0,0},{0,0,0,0}};// 反“7”
int block2[4][4] = {{0,0,0,0},{0,0,1,1},{0,1,1,0},{0,0,0,0}};// 反“z”
int block3[4][4] = {{0,0,0,0},{1,1,0,0},{0,1,1,0},{0,0,0,0}};// 正“z”
int block4[4][4] = {{0,0,0,0},{0,1,0,0},{1,1,1,0},{0,0,0,0}};// 倒“T”
int block5[4][4] = {{0,0,0,0},{0,1,1,0},{0,1,1,0},{0,0,0,0}};// 正方形
int block6[4][4] = {{0,0,0,0},{0,0,0,0},{1,1,1,1},{0,0,0,0}};// 直条
void main()
{
srand((unsigned)time(NULL));//设置随机数种子
char key;
int i , j;
int time;//控制下落时间
console();
my_print();
my_randout();
while( true )//死循环
{
if( check )//如果没有正在下落的方块就执行if里面的
{
check = false;
point_x = 14;//方块最初出现的地方
point_y = 0;
for( i=0 ; i < 4 ; i++)
{
for( j = 0 ; j < 4 ; j++)
{
BLOCK[i][j] = block[i][j];//将提示区的方块数组传到下落的方块数组
}
}
my_printblock();//在point_x,point_y显示方块。
my_randout();//提示区随机换一个方块
}
if (kbhit()) //检测,如果有按键就执行if里面的
{
key = getch();//捕获按键
switch( key )
{
case 72:my_up();//上
break;
case 75:my_lift();//左
break;
case 77:my_right();//右
break;
case 80:my_down();//下
break;
case 32:my_stop();//空格 暂停或开始
break;
case 27:exit(0);//Esc 退出
default: ;
}
}
Sleep(30);//等待0.03秒 0.03秒才能执行一个按键 也降低CPU
if( 0 == ++time % 30 )//控制下落的时间=30*30毫秒
{
my_down();//时间到自动下落一格
}
if( true == check)//当不能下落时
{
for( i=0 ; i < 4 ; i++)
{
for( j = 0 ; j < 4 ; j++)
{
if( 1 == BLOCK[i][j])
scope[point_x / 2 + j][point_y + i] = BLOCK[i][j];//把下落的方块赋值给操作区的数组
//这里的point_x除以2是因为一个小格子占两个横坐标
}
}
my_printblock();
clear();//如果有某一行满了就消除
}
}
}
//设置窗口位置和大小,为了让程序运行得更好看
void console()
{
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); // 获取标准输出设备句柄
CONSOLE_SCREEN_BUFFER_INFO bInfo; // 窗口缓冲区信息
GetConsoleScreenBufferInfo(hOut, &bInfo ); // 获取窗口缓冲区信息
SetConsoleTitle("俄罗斯方块 C版"); // 设置窗口的标题
COORD size = {80, 32};//不能小于默认大小(80,25)
SetConsoleScreenBufferSize(hOut,size); // 重新设置缓冲区大小*/
SMALL_RECT rc = {0,0, 63, 31}; //不能大于缓冲区大小
SetConsoleWindowInfo(hOut,true ,&rc); // 重置窗口大小
}
void my_print()
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_BLUE|FOREGROUND_INTENSITY);//黑底亮蓝字。
for(int i = 1 ; i < 30 ; i++)
printf("■\t\t\t\t■ | |\n");
printf("■■■■■■■■■■■■■■■■■ |---------------------------|\n");//框架
gotoxy(36,0);
printf("---------------------------");
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_GREEN | FOREGROUND_RED |FOREGROUND_INTENSITY);//黑底亮黄字。
gotoxy(40,3);
printf("分 数: %d",fen);
gotoxy(36,6);
printf("下一个方块:");
gotoxy(36,14);
printf("操作方法:");
gotoxy(40,16);
printf("↑:旋转 ↓:沉淀");
gotoxy(40,18);
printf("→:右移 ←:左移");
gotoxy(39,20);
printf("空格键:开始 / 暂停");
gotoxy(39,22);
printf(" Esc:退出");
}
//设置光标输出的位置函数。坐标不能为负数
void gotoxy(int x,int y)//X表示横坐标,Y表示纵坐标。
{
HANDLE app;
COORD pos;
pos.X=x;
pos.Y=y;
app=GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(app,pos);
}
//旋转 将4*4方格顺时针旋转
void my_up()
{
int i,j;
for( i=0 ; i < 4 ; i++)
{
for( j = 0 ; j < 4 ; j++)
{
tem[i][j] = BLOCK[i][j];
if( 1 == BLOCK[i][j])
{
gotoxy(point_x + j*2 , point_y + i);
printf(" ");
}
}
}
for( i=0 ; i < 4 ; i++)
{
for( j = 0 ; j < 4 ; j++)
{
BLOCK[j][3-i] = tem[i][j];
}
}
//以上为旋转。
//下面为防止旋转后超出框架范围
for( j = 0 ; j < 2 ; j++)
{
for( i = 0 ; i < 4 ; i++)
{
if (1 == BLOCK[i][j] && point_x < 2)
{
point_x+=2;
}
else if (1 == BLOCK[i][3-j] && point_x > 24)
{
point_x-=2;
}
}
}
my_printblock();//旋转之后立即显示出来
}
//左移
void my_lift()
{
int i , j ;
for( i = 0 ; i < 3 ; i++ )
for( j = 0 ; j < 4 ; j++ )
{
if(1 == BLOCK[j][i] && (point_x+2*i-1 < 2 || 1 == scope[point_x / 2 + i - 1][point_y + j]))
{
return ;//如果到边缘 或者是左边已经有了方块
}
}
for( i = 0 ; i < 4 ; i++ )
for( j = 0 ; j < 4 ; j++ )
if( 1 == BLOCK[i][j])
{
gotoxy(point_x + j*2 , point_y + i);
printf(" ");//把之前的擦掉
}
point_x -= 2;
my_printblock();
}
void my_right()
{
int i , j ;
for( i = 3 ; i > 0 ; i-- )
for( j = 0 ; j < 4 ; j++ )
{
if(1 == BLOCK[j][i] && ( point_x+2*i+2 > 30 || 1 == scope[point_x / 2 + i + 1][point_y + j]))
{
return ;//如果到边缘 或者是右边已经有了方块
}
}
for( i = 0 ; i < 4 ; i++ )
for( j = 0 ; j < 4 ; j++ )
if( 1 == BLOCK[i][j])
{
gotoxy(point_x + j*2 , point_y + i);
printf(" ");//把之前的擦掉
}
point_x += 2;
my_printblock();
}
void my_down( )
{
int i , j ;
if( true == check)
{
return ;//不能下落直接不执行
}
gotoxy(point_x,point_y);
for( i = 3 ; i > 0 ; i-- )//检测该方格还能不能下落
for( j = 0 ; j < 4 ; j++ )
if ( 1 == BLOCK[i][j] )
{
if (1 == scope[point_x / 2 + j][point_y + i + 1] || point_y + i + 1 > 28 ) //到最下边或是下面已经有方格
{
check = true;
return ;
}
}
for( i = 0 ; i < 4 ; i++ )
for( j = 0 ; j < 4 ; j++ )
if( 1 == BLOCK[i][j])
{
gotoxy(point_x + j*2 , point_y + i);
printf(" ");//能下落,擦除以前的方格
}
point_y++;
my_printblock();//在下一格显示
}
//暂停
void my_stop()
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_RED|FOREGROUND_INTENSITY);
gotoxy(10,10); printf(" ");
gotoxy(10,11); printf(" ■■■■■ ");
gotoxy(10,12); printf(" ■ ■ ");
gotoxy(10,13); printf(" ■ ■ ");
gotoxy(10,14); printf(" ■■■■■ ");
gotoxy(10,15); printf(" ■ ");
gotoxy(10,16); printf(" ■ ");
gotoxy(10,17); printf(" ■ ");
gotoxy(10,18); printf(" ");
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_GREEN|FOREGROUND_INTENSITY);
for(int i = 0 ; i < 9 ; i++)//将暂停掩盖的方块再次显示出来
{
gotoxy(10 , 10 + i );
for(int j = 0 ; j < 7 ; j++ )
{
if (1 == scope[5 + j][10 + i])
{
printf("■");
}
else
{
printf(" ");
}
}
}
}
}
//消除
void clear()
{
int i , j , k , m = 0;
for(i = point_y + 3 ; i >= point_y ; i-- )
{
for( j = 1 ; j < 16 ; j++ )
{
if( 0 == scope[j][i] )
{
break ;
}
}
if ( 16 == j )
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_GREEN|FOREGROUND_INTENSITY);
m++;
for(k=i;k>3;k--)
{
for( j = 1 ; j < 16 ; j++ )
{
scope[j][k] = scope[j][k - 1];
gotoxy(j*2 , k );
if (1 == scope[j][k])
{
printf("■");
}
else
{
printf(" ");
}
}
}
for( j = 1 ; j < 16 ; j++ )
{
scope[j][4] = 0;
}
i++;
}
}
switch(m) {//判断一次消除了几行,来设置得分数
case 1: fen+=100;
break;
case 2: fen+=230;
break;
case 3: fen+=438;
break;
case 4: fen+=854;
break;
default: ;
}
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_GREEN | FOREGROUND_RED |FOREGROUND_INTENSITY);//黑底亮黄色字。
gotoxy(40,3);
printf("分 数: %d",fen);
for( j = 7 ; j < 11 ; j++ )
{
if(1 == scope[j][4])
gameover();
}
}
//随机出现方块
void my_randout()
{
int i,j;
switch( rand()%7 )
{
case 0:for(i=0 ; i < 4 ; i++)
for(j = 0 ; j < 4 ; j++)
block[i][j] = block0[i][j];
break;
case 1: for(i=0 ; i < 4 ; i++)
for(j = 0 ; j < 4 ; j++)
block[i][j] = block1[i][j];
break;
case 2: for(i=0 ; i < 4 ; i++)
for(j = 0 ; j < 4 ; j++)
block[i][j] = block2[i][j];
break;
case 3: for(i=0 ; i < 4 ; i++)
for(j = 0 ; j < 4 ; j++)
block[i][j] = block3[i][j];
break;
case 4: for(i=0 ; i < 4 ; i++)
for( j = 0 ; j < 4 ; j++)
block[i][j] = block4[i][j];
break;
case 5: for( i=0 ; i < 4 ; i++)
for( j = 0 ; j < 4 ; j++)
block[i][j] = block5[i][j];
break;
case 6: for( i=0 ; i < 4 ; i++)
for( j = 0 ; j < 4 ; j++)
block[i][j] = block6[i][j];
break;
default: ;
}
for( i=0 ; i < 4 ; i++)
{
for( j = 0 ; j < 4 ; j++)
{
tem[i][j] = block[i][j];
}
}
switch( rand()%4 )//再设置随机旋转的方向
{
case 0 :
break;
case 1 : for( i=0 ; i < 4 ; i++)//顺时针90度
{
for( j = 0 ; j < 4 ; j++)
{
block[j][3-i] = tem[i][j];
}
}
break;
case 2 : for( i=0 ; i < 4 ; i++)//顺180度
{
for( j = 0 ; j < 4 ; j++)
{
block[3-i][3-j] = tem[i][j];
}
}
break;
case 3 : for( i=0 ; i < 4 ; i++)//顺270度
{
for( j = 0 ; j < 4 ; j++)
{
block[3-j][i] = tem[i][j];
}
}
break;
default: ;
}
//打印提示区的方块
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_RED|FOREGROUND_INTENSITY);//黑底亮红字。
for( i=0 ; i < 4 ; i++)
{
gotoxy(44 , 8 + i);
for( j = 0 ; j < 4 ; j++)
{
if(1 == block[i][j])
{
printf("■");
}
else
{
printf(" ");
}
}
}
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE);//黑底白字
}
//显示方格
void my_printblock()
{
int i , j ;
for( i=0 ; i < 4 ; i++)
{
for( j = 0 ; j < 4 ; j++)
{
if (point_x / 2 + j > 0 )
{
if ( 1 == scope[point_x / 2 + j][point_y + i])
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_GREEN|FOREGROUND_INTENSITY);
gotoxy(point_x + j*2 , point_y + i);
printf("■");
}
else if (1 == BLOCK[i][j])
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE);
gotoxy(point_x + j*2 , point_y + i);
printf("■");
}
}
}
}
}
void gameover()
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED);
gotoxy(4,10); printf(" ");
gotoxy(4,11); printf(" ■■■ ■ ■ ■■■■ ■■■■ ");
gotoxy(4,12); printf(" ■ ■ ■ ■ ■ ■ ■ ");
gotoxy(4,13); printf(" ■ ■ ■ ■ ■■■■ ■■■■ ");
gotoxy(4,14); printf(" ■ ■ ■ ■ ■ ■■ ");
gotoxy(4,15); printf(" ■■■ ■ ■■■■ ■ ■ ");
gotoxy(4,16); printf(" ");
gotoxy(32,17); printf("空格键:重来\tEsc:退出");
switch( getch() )
{
case 32: system("cls");//清屏
console();
my_print();//输出界面
my_randout();
memset(scope, 0, sizeof(int) * 25 * 34);//数组清零
fen = 0;
break;
case 27: exit(0);
break;
default:;
}
}