俄罗斯方块

来源:互联网 发布:盗梦空间limbo 知乎 编辑:程序博客网 时间:2024/05/29 07:38



#include<stdio.h>
#include <windows.h>
#include<conio.h>
#include<time.h>
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:;
 }
}

0 0