/********************************************************************************\ 很久之前就想写“俄罗斯方块”了,现在终于写成了,呵呵 …… !本来在学 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); }}

评论