正文

俄罗斯方块[C/字符模式]2007-05-17 10:16:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/lingdlz/25953.html

分享到:

/********************************************************************************\
     很久之前就想写“俄罗斯方块”了,现在终于写成了,呵呵 …… !本来在学 MFC
 准备搞 Windows 编程离开DOS黑黑的界面,觉得还欠点什么没写,原来以前就打算要写
 “俄罗斯方块”一直没写,于是学了点 MFC 就又钻进了DOS黑界面 …… 现在正值软考
 前夕,哎,软考是没希望了,英语又差得要死,这些烦恼只有在沉醉于Make Code 时才
 能彻底忘掉 ……
     算法不是很好,处理按键不是很敏捷,于是编写对战程序的雄心在没有好算法之前
 只好先打消了。放在这里希望初学者能有所收获 !

     操作说明:回车键:           开始/暂停 
               向上的方向键:     方块变形 
               向下的的方向键:   快速下落
               向左/向右的方向键:向左/右移动方块

 编译环境:      TC3        
 要求显示器能提供:  彩色 43/50 线文本模式否则程序将退出。

 author:江南孤峰  
 data:   2007--5--17
 转载请注明出处:http://blog.programfan.com/blog.asp?blogid=3511
 修改请保留原作者信息,否则视为侵权 !

  点击下载源代码
\********************************************************************************/

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <dos.h>

/*  功能键定义  */
#define ESC         0x011b
#define QUICK_DOWN  0x5000   /* 砖块快速下降       */
#define LEFT        0x4b00
#define RIGHT       0x4d00
#define UP          0x4800
#define ENTER       0x1c0d
#define COMMON_DOWN 0x0011   /* 普通速度下降       */

#define OK          1
#define MAX_X       10       /* 游戏区域的宽度     */
#define MAX_Y       18       /* 游戏区域的高度     */
#define BLOCK_COUNT 7        /* 游戏支持的砖块数目 */
#define INIT_SPEED  200      /* 游戏初始速度       */
#define TEXT_MODE   64       /* 43/50 的文本模式   */
#define ADD_SPEED   20       /* 每升一级速度的增大 */
#define BELL        7        /* 蜂鸣声             */

/***************************** 数 据 结 构 ************************************/

typedef struct{              /* 坐标点                                 */
    int x,y;
}COORD;

typedef struct  {            /* 当前砖块的相关信息                     */
    int shape_n;             /* 砖块的编号                             */
    int shape;               /* 本砖块内的形状编号,用于变形           */
    int shape_count;         /* 砖块总共的变形方式                     */
    int left_top_x;          /* 砖块 4*4 矩阵中的左上角在 矩阵 metrix  */
    int left_top_y;          /* 中的位置,主要用于变形                 */
    COORD dest[4];           /* 4 表示构成每个砖块的字符数目           */
}BLOCK_INFO;

/***************************** 全 局 变 量 ************************************/

int   edge_top,edge_down,edge_left,edge_right; /* 游戏区域屏幕坐标边界 */
int   level, score, speed;                     /* 游戏的状态变量       */
char  metrix[MAX_Y][MAX_X];                    /* 游戏区域矩阵         */
char  video[MAX_Y*MAX_X*2];                    /* 用于屏幕数据移动     */

/* 方块用4*4矩阵表示。写成4*4矩阵就知道是什么形状了,block#x  记录了所有变
 * 形。4*4 的矩阵浪费了很多的内存空间,就因为直线,不过以后可以添加更多的
 * 方块。添加一个方块需要定义该方块的矩阵以及其变形,其变形数目注册到全局
 * 数组 shape[],改变宏 BLOCK_COUNT ,以及在函数 Select_Block()和
 * Get_New_Shape() 中添加代码 。
 */

char  block1[][4][4] = {                       /* 直线 及其变形        */
      { 0,0,0,0, 1,1,1,1, 0,0,0,0, 0,0,0,0 },  /* 注意编号一定要是 0   */
      { 0,1,0,0, 0,1,0,0, 0,1,0,0, 0,1,0,0 }
};
char  block2[][4][4] = {                       /* 田字形               */
      { 1,1,0,0, 1,1,0,0, 0,0,0,0, 0,0,0,0 }
};
char  block3[][4][4] = {                        /* L形及其变形         */
      { 1,0,0,0, 1,0,0,0, 1,1,0,0, 0,0,0,0 },
      { 1,1,1,0, 1,0,0,0, 0,0,0,0, 0,0,0,0 },
      { 0,1,1,0, 0,0,1,0, 0,0,1,0, 0,0,0,0 },
      { 0,0,0,0, 0,0,1,0, 1,1,1,0, 0,0,0,0 }
};
char  block4[][4][4] = {                        /* T 形及其变形        */
      { 0,1,0,0, 1,1,1,0, 0,0,0,0, 0,0,0,0 },
      { 1,0,0,0, 1,1,0,0, 1,0,0,0, 0,0,0,0 },
      { 1,1,1,0, 0,1,0,0, 0,0,0,0, 0,0,0,0 },
      { 0,1,0,0, 1,1,0,0, 0,1,0,0, 0,0,0,0 }
};
char  block5[][4][4] = {
      { 0,1,0,0, 0,1,1,0, 0,0,1,0, 0,0,0,0 },
      { 0,1,1,0, 1,1,0,0, 0,0,0,0, 0,0,0,0 }
};
char  block6[][4][4] = {                        /* 反 L 形及其变形     */
      { 0,0,1,0, 0,0,1,0, 0,1,1,0, 0,0,0,0 },
      { 0,0,0,0, 1,0,0,0, 1,1,1,0, 0,0,0,0 },
      { 1,1,0,0, 1,0,0,0, 1,0,0,0, 0,0,0,0 },
      { 1,1,1,0, 0,0,1,0, 0,0,0,0, 0,0,0,0 }
};
char  block7[][4][4] = {                        /* block5 的反形       */
      { 0,0,1,0, 0,1,1,0, 0,1,0,0, 0,0,0,0 },
      { 1,1,0,0, 0,1,1,0, 0,0,0,0, 0,0,0,0 }
};

int   shape[] = { 2,1,4,4,2,4,2 };              /* 每个砖块的变形数目  */
const char meter_char[] = {
        1, 14, 3, 5, 6, '@', '*', 219
    };                                          /* 构成砖块的字符表    */
const int  block_char_count = 8;                /* 构成砖快的字符数目  */
char  block_char;                               /* 构成当前砖块的字符  */

/***************************** 函 数 定 义**************************************/

/* 初始化屏幕块背景色 */
void Init_Face_Block(int bkColor){
    textbackground(bkColor);
    clrscr();
}

/* 更新游戏成绩 */
void Update_Level_Score(void){
    window(edge_left, edge_top-5, edge_right, edge_top-1);
    textcolor(YELLOW);
    Init_Face_Block(BLACK);
    gotoxy(1,2);     cprintf("Score:%d",score);
    gotoxy(1,4);     cprintf("Level:%d",level);
    window(edge_left+1, edge_top+1, edge_right-1, edge_down-1);
}

/* 打印游戏区域边缘 */
void Print_Edge(void){
    int x, y;
    window(edge_left, edge_top+1, edge_right, edge_down);
    textcolor(CYAN);
    clrscr();
    for(y = 1; y < MAX_Y; y++){
 gotoxy(1,y);
 putchar(block_char);
 gotoxy(MAX_X+1,y);
 putchar(block_char);
    }
    gotoxy(1, MAX_Y);
    for(x = 1; x < MAX_X+2; x++)
 putchar(block_char);
    window(edge_left+1, edge_top+1, edge_right-1, edge_down-1);
    textcolor(YELLOW);
    Init_Face_Block(BLACK);
}

/* 初始化游戏状态数据 */
void Init_Game(void){
    level = 1;
    score = 0;
    speed = INIT_SPEED;
    block_char = meter_char[rand()%block_char_count];
    memset(metrix,0,sizeof(char) * MAX_Y * MAX_X);
    Update_Level_Score();
    Print_Edge();
}

/* 打印相关文本 */
void Print_Text(void){
    window(edge_left-20, edge_top-4, edge_left-2, edge_down-1);
    textcolor(WHITE);
    Init_Face_Block(BLACK);
    gotoxy(1,2);     cprintf("   FUNCTION KEY    ");
    gotoxy(1,4);     cprintf("start game:[Enter] ");
    gotoxy(1,6);     cprintf("pause game:[Enter] ");
    gotoxy(1,8);     cprintf("exit game :[ Esc ] ");
    gotoxy(1,10);    cprintf("move left :[  %c  ] ",27);
    gotoxy(1,12);    cprintf("move right:[  %c  ] ",26);
    gotoxy(1,14);    cprintf("down quick:[  %c  ] ",25);
    gotoxy(1,16);    cprintf("change shape : [%c] ",24);

    window(edge_right+2, edge_top+1, edge_right+11, edge_down-1);
    gotoxy(1,2);     cprintf("QQ GROUP:");
    gotoxy(1,4);     cprintf(" 28011342 ");
    gotoxy(1,6);     cprintf("MY QQ:");
    gotoxy(1,8);     cprintf(" 403324669");
    gotoxy(1,10);    cprintf(" WISH YOU");
    gotoxy(1,12);    cprintf("  HAPPY");
    gotoxy(1,14);    cprintf("   !!!");
}

/* 初始化用户界面 */
void Init_Face(void){
    textcolor(WHITE);
    Init_Face_Block(BLACK);
    gotoxy(edge_left-20, edge_top-8);
    printf(" WELCOME TO PLAY THE GAME OF RUSSIA BLOCK !");
    gotoxy(edge_left-18, edge_down+3);
    printf(" CopyRight @ JianNanGuFeng (2007-2010) ");
    gotoxy(edge_left-10, edge_down+5);
    printf(" Email: lingdlz@163.com");
    window(edge_left-21, edge_top-6, edge_right+12, edge_down+1);
    Init_Face_Block(RED);
    window(edge_left-20, edge_top-5, edge_right+11, edge_down);
    Init_Face_Block(BLACK);
    window(edge_left-1, edge_top-5, edge_left-1, edge_down);
    Init_Face_Block(RED);
    window(edge_right+1, edge_top-5, edge_right+1, edge_down);
    clrscr();
    window(edge_left, edge_top, edge_right+12, edge_top);
    clrscr();
    Print_Text();
}

/* 设置只需初始化一次的变量 */
void Configure_Game(void){
    struct text_info text;

    textmode(TEXT_MODE);
    gettextinfo(&text);
    if(text.screenheight != 43 && text.screenheight != 50){
 puts("The Game Need Text 43/50 Mode !");
 exit(0);
    }
    edge_top   = (text.screenheight - MAX_Y+7) / 2;
    edge_down  = edge_top  + MAX_Y;
    edge_left  = (text.screenwidth  - MAX_X+6) / 2;
    edge_right = edge_left + MAX_X;
}

/* 设置不合法光标尺寸,隐藏光标 */
void Hide_Cursor(void){
    union REGS inregs,outregs;
    inregs.h.ch = 100;
    inregs.h.cl = 100;
    inregs.h.ah = 1;
    int86(0x10,&inregs,&outregs);
}

/* 砖块位置信息存入 pBlock->dest */
void Write_Block_Coord(char block[][4][4], BLOCK_INFO *pBlock){
    int x, y, i, line_add = 3;

    if(pBlock->shape_n == 0)
 line_add = 4;           /* 直线需要检查4*4的矩阵 */
    for(i = y = 0; y < line_add; y++)
 for(x = 0; x < line_add; x++){
     if(block[pBlock->shape][y][x] == 1){
  pBlock->dest[i].x = pBlock->left_top_x + x;
  pBlock->dest[i].y = pBlock->left_top_y + y;
  i++;
     }
 }
}

/* 选入砖块
 * 参数 :pBlock 用于存储选中的砖块的信息
 *        n      砖块的编号
 *        m      砖块内的形状编号
 */
int Select_Block(BLOCK_INFO *pBlock, int next_block, int next_shape){
    int select;

    pBlock->left_top_x = MAX_X / 2 - 2;
    pBlock->left_top_y = 1;
    pBlock->shape_n    = next_block;
    pBlock->shape      = next_shape;
    pBlock->shape_count= shape[next_block];
    switch( pBlock->shape_n ){
 case 0: Write_Block_Coord(block1, pBlock);
  break;
 case 1: Write_Block_Coord(block2, pBlock);
  break;
 case 2: Write_Block_Coord(block3, pBlock);
  break;
 case 3: Write_Block_Coord(block4, pBlock);
  break;
 case 4: Write_Block_Coord(block5, pBlock);
  break;
 case 5: Write_Block_Coord(block6, pBlock);
  break;
 case 6: Write_Block_Coord(block7, pBlock);
  break;
 default:printf("Game Error When Select Block !\n");
  system("pause");
  exit(1);
    }
    return select;
}

/* 检查砖块是否能向 dest 方向移动 */
int Check_Move(int dest, BLOCK_INFO *pBlock, COORD new_dest[]){
    int i;
    switch( dest ){
 case COMMON_DOWN:
 case QUICK_DOWN:
      for(i = 0; i < 4; i++){
   if( metrix[pBlock->dest[i].y+1][pBlock->dest[i].x] ||
                            pBlock->dest[i].y+1 >= MAX_Y )
       return !OK;
   new_dest[i].x = pBlock->dest[i].x;
   new_dest[i].y = pBlock->dest[i].y + 1;
      }
      pBlock -> left_top_y++;
      return OK;
 case LEFT:  for(i = 0; i < 4; i++){
   if( metrix[pBlock->dest[i].y][pBlock->dest[i].x-1] ||
       pBlock->dest[i].x-1 <= 0 )
       return !OK;
   new_dest[i].x = pBlock->dest[i].x - 1;
   new_dest[i].y = pBlock->dest[i].y;
      }
      pBlock -> left_top_x--;
      return OK;
 case RIGHT: for(i = 0; i < 4; i++){
   if( metrix[pBlock->dest[i].y][pBlock->dest[i].x+1] ||
       pBlock->dest[i].x+1 >= MAX_X )
       return !OK;
   new_dest[i].x = pBlock->dest[i].x + 1;
   new_dest[i].y = pBlock->dest[i].y;
      }
      pBlock -> left_top_x++;
      return OK;
 default:    return OK;
    }
}

/* 屏幕显示砖块
 * 参数:dest 记录屏幕打印位置
 */
void Show_Block(COORD dest[]){
    int i;
    for(i = 0; i < 4; i++){
 gotoxy(dest[i].x, dest[i].y);
 putchar(block_char);
    }
}

/* 检查是否命中一行, 如果命中则更新 level, score  */
void Test_GetLine(void){
    int flag, x, y;
    char *p_dest,*p_sour;

    for(y = 4; y < MAX_Y; y++){
 for(flag = x = 1; x < MAX_X; x++){
     if(metrix[y][x] ==0){
   flag = 0;
   break;
     }
 }
 if(flag == 1){
     gettext(edge_left+1,edge_top+2,edge_right-1,edge_top+y-1,video);
     puttext(edge_left+1,edge_top+3,edge_right-1,edge_top+y,video);
     p_dest = &metrix[y][MAX_X-1];
     p_sour = p_dest - MAX_X;
     for(; p_sour != (char*)metrix; p_dest--, p_sour--)
   *p_dest = *p_sour;
     score += 100;
     if(score >= 500 * level){
   speed -= ADD_SPEED;
   level++;
   putchar(BELL);
     }
     Update_Level_Score();
 }
    }
}

/* 更新大矩阵,即屏幕上的游戏区域 */
int Update_Metrix(BLOCK_INFO *pBlock){
    int i,x,y;

    for(i = 0; i < 4; i++){
 if(metrix[pBlock->dest[i].y][pBlock->dest[i].x])
     return !OK;
 metrix[pBlock->dest[i].y][pBlock->dest[i].x] = 1;
    }
    Test_GetLine();
    return OK;
}

/* 移动砖块到 new_dest 位置 */
void Move_Block(COORD new_dest[],BLOCK_INFO *pBlock){
    int i;
    for(i = 0; i < 4; i++){
 gotoxy(pBlock->dest[i].x, pBlock->dest[i].y);
 putchar(' ');         
 pBlock->dest[i].x = new_dest[i].x;
 pBlock->dest[i].y = new_dest[i].y;
    }
    Show_Block(pBlock->dest);  
    delay(speed);             
}

/* 动态的游戏结束画面 */
void Print_Over(char c, int y){
    int x;
    for(x = 1; x < MAX_X; x++){
 gotoxy(x,y);
 putchar(c);
    }
    delay(50);
}

/* 等待按开始键开始游戏 */
void Wait_Start(void){
    int key;
    putchar(BELL);
    do{
 key = bioskey(0);
    }while(key != ENTER && key != ESC);
    if(key == ESC)
  exit(0);
}

/* 游戏结束,显示结束画面 */
void Show_GameOver(void){
    int x,y;
    for(y = MAX_Y - 1; y > 0; y--)
 Print_Over(block_char,y);
    for(y = 1; y < MAX_Y; y++)
 Print_Over(' ',y);
    window(edge_left+1, edge_top+4, edge_right-1, edge_top+8);
    textattr(BLINK+WHITE+(RED<<4));
    clrscr();
    gotoxy(1,2);    printf(" Game ");
    gotoxy(1,3);    printf("    Over");
    gotoxy(1,4);    printf(" !!! ");
    putchar(BELL) ;
    Wait_Start();
    window(edge_left+1, edge_top+1, edge_right-1, edge_down-1);
    textcolor(YELLOW);
    Init_Face_Block(BLACK);
}

/* 获取砖块的相对坐标--在矩阵 metrix 中的位置
 * 参数说明:pBkSp   用于临时存储砖块变形后的相关信息
 *           pBlock  当前砖块的有关信息
 */
void Get_New_Shape(BLOCK_INFO *pBkSp, BLOCK_INFO *pBlock){
    int x, y;

    if(pBlock->shape+1 < pBlock->shape_count)
 pBkSp->shape = pBlock->shape + 1;
    else
 pBkSp->shape  = 0;
    pBkSp->left_top_x = pBlock->left_top_x;
    pBkSp->left_top_y = pBlock->left_top_y;
    pBkSp->shape_n    = pBlock->shape_n;
    switch( pBlock->shape_n ){
 case 0: Write_Block_Coord(block1, pBkSp);
  break;
 case 1: Write_Block_Coord(block2, pBkSp);
  break;
 case 2: Write_Block_Coord(block3, pBkSp);
  break;
 case 3: Write_Block_Coord(block4, pBkSp);
  break;
 case 4: Write_Block_Coord(block5, pBkSp);
  break;
 case 5: Write_Block_Coord(block6, pBkSp);
  break;
 case 6: Write_Block_Coord(block7, pBkSp);
  break;
 default:printf("Game Error When Change Block Shape !\n");
  system("pause");
  exit(1);
    }
}

/* 砖块变形 */
void Change_Shape(BLOCK_INFO *pBlock){
    int   i, x, y, line_add = 3;
    BLOCK_INFO temp;

    if(pBlock -> shape_count == 1)
  return ;
    else if(pBlock->shape_n == 0)
  line_add = 4;
    for(y = pBlock->left_top_y; y < pBlock->left_top_y + line_add; y++)
 for(x = pBlock->left_top_x; x < pBlock->left_top_x + line_add; x++){
     if(metrix[y][x] || y >= MAX_Y || x < 1 || x >= MAX_X)
  return ;
    }
    Get_New_Shape(&temp, pBlock);
    Move_Block(temp.dest,pBlock);
    pBlock->shape = temp.shape;
    for(i = 0; i < 4; i++){
  pBlock->dest[i].x = temp.dest[i].x;
  pBlock->dest[i].y = temp.dest[i].y;
    }
}

/* 显示下一个砖块 */
void Print_Next_Block(BLOCK_INFO *pBlock){
    COORD temp[4];
    int   i;

    for(i = 0; i < 4; i++){
 temp[i].x = pBlock->dest[i].x - pBlock->left_top_x + 2;
 temp[i].y = pBlock->dest[i].y - pBlock->left_top_y + 2;
    }
    window(edge_right+4, edge_top-5, edge_right+10, edge_top-1);
    clrscr();
    Show_Block(temp);
    window(edge_left+1, edge_top+1, edge_right-1, edge_down-1);
}

int main(void){
    int   dest, key, flag, speed_save;
    int   next_block, next_shape;
    COORD      new_dest[4];
    BLOCK_INFO block_info,block_info_next;

    /* system("full"); 注意找到 full.exe 放到 TC.exe 同目录下,进入全屏模式 */
    Configure_Game();
    Hide_Cursor();
    Init_Face();
    Init_Game();
    Select_Block(&block_info_next, 0, 0);
    Print_Next_Block(&block_info_next);
    Wait_Start();
    for(flag = 0 ;; ){
 if(flag == 0){
            memcpy(&block_info, &block_info_next, sizeof(BLOCK_INFO));
     next_block = rand() % BLOCK_COUNT;
     next_shape = rand() % shape[next_block];
     Select_Block(&block_info_next, next_block, next_shape);
     Print_Next_Block(&block_info_next);
     Show_Block(block_info.dest);
     flag = 1;
 }
 if(!kbhit())
     dest = COMMON_DOWN;
 else{
     key = bioskey( 0 );
     switch( key ){
  case QUICK_DOWN:
        dest = QUICK_DOWN;
        break;
  case LEFT:   dest = LEFT;
        break;
  case RIGHT:  dest = RIGHT;
        break;
  case UP:     Change_Shape(&block_info);
        continue;
  case ENTER:  Wait_Start();
        break;
  case ESC:    return 0;
  default:     dest = COMMON_DOWN;
        break;
     }
 }
 if(Check_Move(dest, &block_info, new_dest) != OK){
     if(dest == COMMON_DOWN || dest == QUICK_DOWN){
  if(Update_Metrix(&block_info) != OK){
      Show_GameOver();
      Init_Game();
  }
  flag = 0;
     }
 }
 else if(dest == QUICK_DOWN){
     speed_save = speed;
     speed = ADD_SPEED * 3;
     Move_Block(new_dest, &block_info);
     if(Check_Move(dest, &block_info, new_dest) == OK)
   Move_Block(new_dest, &block_info);
     speed = speed_save - ADD_SPEED * 3 + speed;
 }
 else
     Move_Block(new_dest, &block_info);
   }
}

阅读(5124) | 评论(6)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

loading...
您需要登录后才能评论,请 登录 或者 注册