正文

俄罗斯方块[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);   }}

阅读(5298) | 评论(6)


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

评论

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